* [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support
@ 2026-03-17 10:33 Andre Przywara
2026-03-17 10:33 ` [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding Andre Przywara
` (8 more replies)
0 siblings, 9 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, linux-kernel,
vwadekar, Trilok Soni, devicetree, Nirmoy Das,
Krzysztof Kozlowski, linux-arm-kernel
Hi all,
this is version 2 of the Live Firmware Activation kernel support. There
were some significant changes to the code compared to the previous v1
post [1]: the images are now managed using an embedded kobject, joined
by a kset representing the /sys/firmware/lfa directory. The locking has
been overhauled, there is no longer a global lock, but just the kset
list lock, and a readers/writer lock when doing the actual SMC accesses.
Also this series now includes support for the ACPI notification, as
contributed by Veda [2] (many thanks for that!), and support for the DT
interrupt. Also there is a new sysfs switch file to allow the automatic
activation.
This is now multiple patches, mostly to help review and to give credit
to Veda's work. If people agree, some of the patches can be squashed for
submission, eventually.
More detailed changelog below.
==============================
This series implements the kernel side support of the Arm Live
Firmware Activation (LFA) specification [3]. LFA enables the activation
of updated firmware components without requiring a system reboot,
reducing downtime and allowing quicker deployment of critical bug fixes
in environments such as data centers and hyperscale systems.
It requires explicit firmware support, both via an agent running in EL3
(for instance in TF-A, already merged), but also in the firmware
component to be activated. TF-RMM recently merged support for this.
Unlike the usual firmware update process (which may use tools like
fwupd), LFA focuses solely on the activation of an already updated
firmware component, called "pending activation" in LFA lingo. This works
by signalling the LFA agent (part of the EL3 runtime firmware) via an
SMC call, which then does the heavy lifting of the live update, in
cooperation with the to-be-updated firmware component.
Key features of the driver:
* Detects LFA support in system firmware (EL3).
* Lists all firmware components that support live activation, identified
by their GUID.
* Exposes component attributes (e.g., activation capability, and
activation pending) via sysfs under /sys/firmware/lfa/<GUID>/.
* Provides interfaces to:
- Trigger activation of an updated firmware component.
- Cancel an ongoing activation if required.
A more detailed list of features can be found in patch 2/8.
Based on v7.0-rc1.
This work is conceptually similar to Intel’s Platform Firmware Runtime
Update and telemetry (PFRUT) [4] and TDX module updates [5], but
targets Arm platforms. The driver has been used to successfully activate
a Realm Management Monitor (RMM) firmware image in a controlled test
environment. RMM is analogous to Intel’s TDX module.
There is effort on similar work from the OCP [6]. Future work may
include integration with utilities like fwupd to automatically select
the appropriate driver, based on platform architecture, for Live/Runtime
firmware updates.
Please have a look, test and comment!
Best regards,
Salman and Andre
Changelog v1 .. v2:
- restrict build to arm64 (the LFA spec only supports AArch64)
- rename and extend central data structure to fw_image
- use separate GPR register sets for some SMC calls
- provide wrapper for error messages to prevent out-of-bound access
- return GUID in the "name" sysfs file when image is unknown
- fix wrong attribute in pending version number show function
- add missing include files and order them properly
- fix memory leaks in error cleanup paths
- handle lifetime using embedded kobjects and a kset
- drop global lfa_lock, use kset list lock and kobject refcount instead
- add DT binding documentation
- add timeout and watchdog re-arming (contributed by Veda)
- relax timeout period and do not block while waiting
- register ACPI notification (contributed by Veda) and DT interrupt
- refactor ACPI notification code to allow sharing with DT code
- use faux device instead of platform driver
- add auto_activate file to control automatic activation
- introduce rwsem mutex to prevent using stale sequence ID
- use labels and goto instead of infinite loop when retrying activation
- initialise workqueue only once (thanks to Nirmoy)
- various cleanups on reported messages and code formatting
- rebase on top of v7.0-rc1
Changelog RFC .. v1:
- Updated SMCCC version 1.1 to 1.2 per the LFA specification requirement.
- Changed "image_props" array to a linked list to support the dynamic
removal and addition of firmware images.
- Added code to refresh firmware images following a successful activation.
- Added a work_queue to handle the removal of firmware image attribute
from it's respective kobject "_store" handle.
- Refactored prime and activate into separate functions.
- Kernel config for LFA now defaults to "y" i.e. included by default.
- Added individual kernel attribute files removal when removing the
respective kobjects using kobject_put().
- mutex_lock added to activate_fw_image() and prime_fw_image() calls.
- Renamed create_fw_inventory to update_fw_image_node.
- Renamed create_fw_images_tree to update_fw_images_tree.
- Added two more attributes due to specs update from bet0 to bet1:
current_version: For retrieval of the current firmware's version info.
pending_version: For retrieval of the pending firmware's version info.
- Minor changes such as, improved firmware image names, and code comments.
- do...while loops refactored to for(;;) loops.
[1] https://lore.kernel.org/linux-arm-kernel/20260119122729.287522-1-salman.nabi@arm.com/
[2] https://lore.kernel.org/linux-arm-kernel/20260210224023.2341728-1-vvidwans@nvidia.com/
[3] https://developer.arm.com/documentation/den0147/latest/
[4] https://lore.kernel.org/all/cover.1631025237.git.yu.c.chen@intel.com/
[5] https://lore.kernel.org/all/20250523095322.88774-1-chao.gao@intel.com/
[6] https://www.opencompute.org/documents/hyperscale-cpu-impactless-firmware-updates-requirements-specification-v0-7-9-29-2025-pdf
Andre Przywara (4):
dt-bindings: arm: Add Live Firmware Activation binding
firmware: smccc: lfa: Add auto_activate sysfs file
firmware: smccc: lfa: Register DT interrupt
firmware: smccc: lfa: introduce SMC access lock
Salman Nabi (1):
firmware: smccc: Add support for Live Firmware Activation (LFA)
Vedashree Vidwans (3):
firmware: smccc: lfa: Move image rescanning
firmware: smccc: lfa: Add timeout and trigger watchdog
firmware: smccc: lfa: Register ACPI notification
.../devicetree/bindings/arm/arm,lfa.yaml | 45 +
drivers/firmware/smccc/Kconfig | 10 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/lfa_fw.c | 1008 +++++++++++++++++
4 files changed, 1064 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/arm,lfa.yaml
create mode 100644 drivers/firmware/smccc/lfa_fw.c
--
2.43.0
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-18 8:04 ` Krzysztof Kozlowski
2026-03-17 10:33 ` [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA) Andre Przywara
` (7 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: vsethi, Salman Nabi, devicetree, linux-kernel, vwadekar,
Trilok Soni, Nirmoy Das, linux-arm-kernel
The Arm Live Firmware Activation spec [1] describes updating firmware
images during runtime, without requiring a reboot. Update images might
be deployed out-of-band, for instance via a BMC, in this case the OS
needs to be notified about the availability of a new image.
This binding describes an interrupt that could be triggered by the
platform, to notify about any changes.
[1] https://developer.arm.com/documentation/den0147/latest/
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../devicetree/bindings/arm/arm,lfa.yaml | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/arm,lfa.yaml
diff --git a/Documentation/devicetree/bindings/arm/arm,lfa.yaml b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
new file mode 100644
index 000000000000..92f0564fd672
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/arm,lfa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm Live Firmware Activation (LFA)
+
+maintainers:
+ - Andre Przywara <andre.przywara@arm.com>
+ - Sudeep Holla <sudeep.holla@arm.com>
+
+description:
+ The Arm Live Firmware Activation (LFA) specification [1] describes a
+ firmware interface to activate an updated firmware at runtime, without
+ requiring a reboot. Updates might be supplied out-of-band, for instance
+ via a BMC, in which case the platform needs to notify an OS about pending
+ image updates.
+ [1] https://developer.arm.com/documentation/den0147/latest/
+
+properties:
+ compatible:
+ const: arm,lfa
+
+ interrupts:
+ maxItems: 1
+ description: notification interrupt for changed firmware image status
+
+required:
+ - compatible
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ firmware {
+ arm-lfa {
+ compatible = "arm,lfa";
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA)
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
2026-03-17 10:33 ` [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-18 8:09 ` Krzysztof Kozlowski
2026-03-17 10:33 ` [PATCH v2 3/8] firmware: smccc: lfa: Move image rescanning Andre Przywara
` (6 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
From: Salman Nabi <salman.nabi@arm.com>
The Arm Live Firmware Activation (LFA) is a specification [1] to describe
activating firmware components without a reboot. Those components
(like TF-A's BL31, EDK-II, TF-RMM, secure paylods) would be updated the
usual way: via fwupd, FF-A or other secure storage methods, or via some
IMPDEF Out-Of-Bound method. The user can then activate this new firmware,
at system runtime, without requiring a reboot.
The specification covers the SMCCC interface to list and query available
components and eventually trigger the activation.
Add a new directory under /sys/firmware to present firmware components
capable of live activation. Each of them is a directory under lfa/,
and is identified via its GUID. The activation will be triggered by echoing
"1" into the "activate" file:
==========================================
/sys/firmware/lfa # ls -l . 6c*
.:
total 0
drwxr-xr-x 2 0 0 0 Jan 19 11:33 47d4086d-4cfe-9846-9b95-2950cbbd5a00
drwxr-xr-x 2 0 0 0 Jan 19 11:33 6c0762a6-12f2-4b56-92cb-ba8f633606d9
drwxr-xr-x 2 0 0 0 Jan 19 11:33 d6d0eea7-fcea-d54b-9782-9934f234b6e4
6c0762a6-12f2-4b56-92cb-ba8f633606d9:
total 0
--w------- 1 0 0 4096 Jan 19 11:33 activate
-r--r--r-- 1 0 0 4096 Jan 19 11:33 activation_capable
-r--r--r-- 1 0 0 4096 Jan 19 11:33 activation_pending
--w------- 1 0 0 4096 Jan 19 11:33 cancel
-r--r--r-- 1 0 0 4096 Jan 19 11:33 cpu_rendezvous
-r--r--r-- 1 0 0 4096 Jan 19 11:33 current_version
-rw-r--r-- 1 0 0 4096 Jan 19 11:33 force_cpu_rendezvous
-r--r--r-- 1 0 0 4096 Jan 19 11:33 may_reset_cpu
-r--r--r-- 1 0 0 4096 Jan 19 11:33 name
-r--r--r-- 1 0 0 4096 Jan 19 11:33 pending_version
/sys/firmware/lfa/6c0762a6-12f2-4b56-92cb-ba8f633606d9 # grep . *
grep: activate: Permission denied
activation_capable:1
activation_pending:1
grep: cancel: Permission denied
cpu_rendezvous:1
current_version:0.0
force_cpu_rendezvous:1
may_reset_cpu:0
name:TF-RMM
pending_version:0.0
/sys/firmware/lfa/6c0762a6-12f2-4b56-92cb-ba8f633606d9 # echo 1 > activate
[ 2825.797871] Arm LFA: firmware activation succeeded.
/sys/firmware/lfa/6c0762a6-12f2-4b56-92cb-ba8f633606d9 #
==========================================
[1] https://developer.arm.com/documentation/den0147/latest/
Signed-off-by: Salman Nabi <salman.nabi@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/Kconfig | 10 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/lfa_fw.c | 721 ++++++++++++++++++++++++++++++++
3 files changed, 732 insertions(+)
create mode 100644 drivers/firmware/smccc/lfa_fw.c
diff --git a/drivers/firmware/smccc/Kconfig b/drivers/firmware/smccc/Kconfig
index 15e7466179a6..7fd646d515f8 100644
--- a/drivers/firmware/smccc/Kconfig
+++ b/drivers/firmware/smccc/Kconfig
@@ -23,3 +23,13 @@ config ARM_SMCCC_SOC_ID
help
Include support for the SoC bus on the ARM SMCCC firmware based
platforms providing some sysfs information about the SoC variant.
+
+config ARM_LFA
+ tristate "Arm Live Firmware activation support"
+ depends on HAVE_ARM_SMCCC_DISCOVERY && ARM64
+ default y
+ help
+ Include support for triggering a Live Firmware Activation (LFA),
+ which allows to upgrade certain firmware components without a reboot.
+ This is described in the Arm DEN0147 specification, and relies on
+ a firmware agent running in EL3.
diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
index 40d19144a860..a6dd01558a94 100644
--- a/drivers/firmware/smccc/Makefile
+++ b/drivers/firmware/smccc/Makefile
@@ -2,3 +2,4 @@
#
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
+obj-$(CONFIG_ARM_LFA) += lfa_fw.o
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
new file mode 100644
index 000000000000..284b7c18d3d0
--- /dev/null
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -0,0 +1,721 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Arm Limited
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/array_size.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/psci.h>
+#include <linux/stop_machine.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/uuid.h>
+#include <linux/workqueue.h>
+
+#include <uapi/linux/psci.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "Arm LFA: " fmt
+
+/* LFA v1.0b0 specification */
+#define LFA_1_0_FN_BASE 0xc40002e0
+#define LFA_1_0_FN(n) (LFA_1_0_FN_BASE + (n))
+
+#define LFA_1_0_FN_GET_VERSION LFA_1_0_FN(0)
+#define LFA_1_0_FN_CHECK_FEATURE LFA_1_0_FN(1)
+#define LFA_1_0_FN_GET_INFO LFA_1_0_FN(2)
+#define LFA_1_0_FN_GET_INVENTORY LFA_1_0_FN(3)
+#define LFA_1_0_FN_PRIME LFA_1_0_FN(4)
+#define LFA_1_0_FN_ACTIVATE LFA_1_0_FN(5)
+#define LFA_1_0_FN_CANCEL LFA_1_0_FN(6)
+
+/* CALL_AGAIN flags (returned by SMC) */
+#define LFA_PRIME_CALL_AGAIN BIT(0)
+#define LFA_ACTIVATE_CALL_AGAIN BIT(0)
+
+/* LFA return values */
+#define LFA_SUCCESS 0
+#define LFA_NOT_SUPPORTED 1
+#define LFA_BUSY 2
+#define LFA_AUTH_ERROR 3
+#define LFA_NO_MEMORY 4
+#define LFA_CRITICAL_ERROR 5
+#define LFA_DEVICE_ERROR 6
+#define LFA_WRONG_STATE 7
+#define LFA_INVALID_PARAMETERS 8
+#define LFA_COMPONENT_WRONG_STATE 9
+#define LFA_INVALID_ADDRESS 10
+#define LFA_ACTIVATION_FAILED 11
+
+/*
+ * Not error codes described by the spec, but used internally when
+ * PRIME/ACTIVATE calls return with the CALL_AGAIN bit set.
+ */
+#define LFA_TIMED_OUT 32
+#define LFA_CALL_AGAIN 33
+
+#define LFA_ERROR_STRING(name) \
+ [name] = #name
+
+static const char * const lfa_error_strings[] = {
+ LFA_ERROR_STRING(LFA_SUCCESS),
+ LFA_ERROR_STRING(LFA_NOT_SUPPORTED),
+ LFA_ERROR_STRING(LFA_BUSY),
+ LFA_ERROR_STRING(LFA_AUTH_ERROR),
+ LFA_ERROR_STRING(LFA_NO_MEMORY),
+ LFA_ERROR_STRING(LFA_CRITICAL_ERROR),
+ LFA_ERROR_STRING(LFA_DEVICE_ERROR),
+ LFA_ERROR_STRING(LFA_WRONG_STATE),
+ LFA_ERROR_STRING(LFA_INVALID_PARAMETERS),
+ LFA_ERROR_STRING(LFA_COMPONENT_WRONG_STATE),
+ LFA_ERROR_STRING(LFA_INVALID_ADDRESS),
+ LFA_ERROR_STRING(LFA_ACTIVATION_FAILED)
+};
+
+enum image_attr_names {
+ LFA_ATTR_NAME,
+ LFA_ATTR_CURRENT_VERSION,
+ LFA_ATTR_PENDING_VERSION,
+ LFA_ATTR_ACT_CAPABLE,
+ LFA_ATTR_ACT_PENDING,
+ LFA_ATTR_MAY_RESET_CPU,
+ LFA_ATTR_CPU_RENDEZVOUS,
+ LFA_ATTR_FORCE_CPU_RENDEZVOUS,
+ LFA_ATTR_ACTIVATE,
+ LFA_ATTR_CANCEL,
+ LFA_ATTR_NR_IMAGES
+};
+
+struct fw_image {
+ struct kobject kobj;
+ const char *image_name;
+ int fw_seq_id;
+ u64 current_version;
+ u64 pending_version;
+ bool activation_capable;
+ bool activation_pending;
+ bool may_reset_cpu;
+ bool cpu_rendezvous;
+ bool cpu_rendezvous_forced;
+ struct kobj_attribute image_attrs[LFA_ATTR_NR_IMAGES];
+};
+
+static struct fw_image *kobj_to_fw_image(struct kobject *kobj)
+{
+ return container_of(kobj, struct fw_image, kobj);
+}
+
+/* A UUID split over two 64-bit registers */
+struct uuid_regs {
+ u64 uuid_lo;
+ u64 uuid_hi;
+};
+
+/* A list of known GUIDs, to be shown in the "name" sysfs file. */
+static const struct fw_image_uuid {
+ const char *name;
+ const char *uuid;
+} fw_images_uuids[] = {
+ {
+ .name = "TF-A BL31 runtime",
+ .uuid = "47d4086d-4cfe-9846-9b95-2950cbbd5a00",
+ },
+ {
+ .name = "BL33 non-secure payload",
+ .uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4",
+ },
+ {
+ .name = "TF-RMM",
+ .uuid = "6c0762a6-12f2-4b56-92cb-ba8f633606d9",
+ },
+};
+
+static struct kset *lfa_kset;
+static struct workqueue_struct *fw_images_update_wq;
+static struct work_struct fw_images_update_work;
+static struct attribute *image_default_attrs[LFA_ATTR_NR_IMAGES + 1];
+
+static const struct attribute_group image_attr_group = {
+ .attrs = image_default_attrs,
+};
+
+static const struct attribute_group *image_default_groups[] = {
+ &image_attr_group,
+ NULL
+};
+
+static int update_fw_images_tree(void);
+
+static const char *lfa_error_string(int error)
+{
+ if (error > 0)
+ return lfa_error_strings[LFA_SUCCESS];
+
+ error = -error;
+ if (error < ARRAY_SIZE(lfa_error_strings))
+ return lfa_error_strings[error];
+ if (error == -LFA_TIMED_OUT)
+ return "timed out";
+
+ return lfa_error_strings[LFA_DEVICE_ERROR];
+}
+
+static void image_release(struct kobject *kobj)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ kfree(image);
+}
+
+static const struct kobj_type image_ktype = {
+ .release = image_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = image_default_groups,
+};
+
+static void delete_fw_image_node(struct fw_image *image)
+{
+ kobject_del(&image->kobj);
+ kobject_put(&image->kobj);
+}
+
+static void remove_invalid_fw_images(struct work_struct *work)
+{
+ struct kobject *kobj, *tmp;
+ struct list_head images_to_delete = LIST_HEAD_INIT(images_to_delete);
+
+ /*
+ * Remove firmware images including directories that are no longer
+ * present in the LFA agent after updating the existing ones.
+ * Delete list images before calling kobject_del() and kobject_put() on
+ * them. Kobject_del() uses kset->list_lock itself which can cause lock
+ * recursion, and kobject_put() may sleep.
+ */
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry_safe(kobj, tmp, &lfa_kset->list, entry) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ if (image->fw_seq_id == -1)
+ list_move_tail(&kobj->entry, &images_to_delete);
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
+ /*
+ * Now safely remove the sysfs kobjects for the deleted list items
+ */
+ list_for_each_entry_safe(kobj, tmp, &images_to_delete, entry) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ delete_fw_image_node(image);
+ }
+}
+
+static void set_image_flags(struct fw_image *image, int seq_id,
+ u32 image_flags, u64 reg_current_ver,
+ u64 reg_pending_ver)
+{
+ image->fw_seq_id = seq_id;
+ image->current_version = reg_current_ver;
+ image->pending_version = reg_pending_ver;
+ image->activation_capable = !!(image_flags & BIT(0));
+ image->activation_pending = !!(image_flags & BIT(1));
+ image->may_reset_cpu = !!(image_flags & BIT(2));
+ /* cpu_rendezvous_optional bit has inverse logic in the spec */
+ image->cpu_rendezvous = !(image_flags & BIT(3));
+}
+
+static unsigned long get_nr_lfa_components(void)
+{
+ struct arm_smccc_1_2_regs reg = { 0 };
+
+ reg.a0 = LFA_1_0_FN_GET_INFO;
+ reg.a1 = 0; /* lfa_info_selector = 0 */
+
+ arm_smccc_1_2_invoke(®, ®);
+ if (reg.a0 != LFA_SUCCESS)
+ return reg.a0;
+
+ return reg.a1;
+}
+
+static int lfa_cancel(void *data)
+{
+ struct fw_image *image = data;
+ struct arm_smccc_1_2_regs reg = { 0 };
+
+ reg.a0 = LFA_1_0_FN_CANCEL;
+ reg.a1 = image->fw_seq_id;
+ arm_smccc_1_2_invoke(®, ®);
+
+ /*
+ * When firmware activation is called with "skip_cpu_rendezvous=1",
+ * LFA_CANCEL can fail with LFA_BUSY if the activation could not be
+ * cancelled.
+ */
+ if (reg.a0 == LFA_SUCCESS) {
+ pr_info("Activation cancelled for image %s\n",
+ image->image_name);
+ } else {
+ pr_err("Activation not cancelled for image %s: %s\n",
+ image->image_name, lfa_error_string(reg.a0));
+ return -EINVAL;
+ }
+
+ return reg.a0;
+}
+
+static const char *get_image_name(const struct fw_image *image)
+{
+ if (image->image_name && image->image_name[0] != '\0')
+ return image->image_name;
+
+ return kobject_name(&image->kobj);
+}
+
+/*
+ * Try a single activation call. The smc_lock writer lock must be held,
+ * and it must be called from inside stop_machine() when CPU rendezvous is
+ * required.
+ */
+static int call_lfa_activate(void *data)
+{
+ struct fw_image *image = data;
+ struct arm_smccc_1_2_regs reg = { 0 }, res;
+
+ reg.a0 = LFA_1_0_FN_ACTIVATE;
+ reg.a1 = image->fw_seq_id;
+ /*
+ * As we do not support updates requiring a CPU reset (yet),
+ * we pass 0 in reg.a3 and reg.a4, holding the entry point and
+ * context ID respectively.
+ * cpu_rendezvous_forced is set by the administrator, via sysfs,
+ * cpu_rendezvous is dictated by each firmware component.
+ */
+ reg.a2 = !(image->cpu_rendezvous_forced || image->cpu_rendezvous);
+ arm_smccc_1_2_invoke(®, &res);
+
+ if ((long)res.a0 < 0)
+ return (long)res.a0;
+
+ if (res.a1 & LFA_ACTIVATE_CALL_AGAIN)
+ return -LFA_CALL_AGAIN;
+
+ return 0;
+}
+
+static int activate_fw_image(struct fw_image *image)
+{
+ struct kobject *kobj;
+ int ret;
+
+retry:
+ if (image->cpu_rendezvous_forced || image->cpu_rendezvous)
+ ret = stop_machine(call_lfa_activate, image, cpu_online_mask);
+ else
+ ret = call_lfa_activate(image);
+
+ if (!ret) {
+ /*
+ * Invalidate fw_seq_ids (-1) for all images as the seq_ids
+ * and the number of firmware images in the LFA agent may
+ * change after a successful activation attempt.
+ * Negate all image flags as well.
+ */
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry(kobj, &lfa_kset->list, entry) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ set_image_flags(image, -1, 0b1000, 0, 0);
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
+ update_fw_images_tree();
+
+ /*
+ * Removing non-valid image directories at the end of an
+ * activation.
+ * We can't remove the sysfs attributes while in the respective
+ * _store() handler, so have to postpone the list removal to a
+ * workqueue.
+ */
+ queue_work(fw_images_update_wq, &fw_images_update_work);
+
+ return 0;
+ }
+
+ if (ret == -LFA_CALL_AGAIN)
+ goto retry;
+
+ lfa_cancel(image);
+
+ pr_err("LFA_ACTIVATE for image %s failed: %s\n",
+ get_image_name(image), lfa_error_string(ret));
+
+ return ret;
+}
+
+static int prime_fw_image(struct fw_image *image)
+{
+ struct arm_smccc_1_2_regs reg = { 0 }, res;
+
+ if (image->may_reset_cpu) {
+ pr_err("CPU reset not supported by kernel driver\n");
+
+ return -EINVAL;
+ }
+
+ reg.a0 = LFA_1_0_FN_PRIME;
+retry:
+ /*
+ * LFA_PRIME will return 1 in reg.a1 if the firmware priming
+ * is still in progress. In that case LFA_PRIME will need to
+ * be called again.
+ * reg.a1 will become 0 once the prime process completes.
+ */
+ reg.a1 = image->fw_seq_id;
+ arm_smccc_1_2_invoke(®, &res);
+ if ((long)res.a0 < 0) {
+ pr_err("LFA_PRIME for image %s failed: %s\n",
+ get_image_name(image),
+ lfa_error_string(res.a0));
+
+ return res.a0;
+ }
+
+ if (res.a1 & LFA_PRIME_CALL_AGAIN)
+ goto retry;
+
+ return 0;
+}
+
+static ssize_t name_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%s\n", image->image_name);
+}
+
+static ssize_t activation_capable_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%d\n", image->activation_capable);
+}
+
+static void update_fw_image_pending(struct fw_image *image)
+{
+ struct arm_smccc_1_2_regs reg = { 0 };
+
+ reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+ reg.a1 = image->fw_seq_id;
+ arm_smccc_1_2_invoke(®, ®);
+
+ if (reg.a0 == LFA_SUCCESS)
+ image->activation_pending = !!(reg.a3 & BIT(1));
+}
+
+static ssize_t activation_pending_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ /*
+ * Activation pending status can change anytime thus we need to update
+ * and return its current value
+ */
+ update_fw_image_pending(image);
+
+ return sysfs_emit(buf, "%d\n", image->activation_pending);
+}
+
+static ssize_t may_reset_cpu_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%d\n", image->may_reset_cpu);
+}
+
+static ssize_t cpu_rendezvous_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%d\n", image->cpu_rendezvous);
+}
+
+static ssize_t force_cpu_rendezvous_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ int ret;
+
+ ret = kstrtobool(buf, &image->cpu_rendezvous_forced);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t force_cpu_rendezvous_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%d\n", image->cpu_rendezvous_forced);
+}
+
+static ssize_t current_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ u32 maj, min;
+
+ maj = image->current_version >> 32;
+ min = image->current_version & 0xffffffff;
+
+ return sysfs_emit(buf, "%u.%u\n", maj, min);
+}
+
+static ssize_t pending_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ struct arm_smccc_1_2_regs reg = { 0 };
+
+ /*
+ * Similar to activation pending, this value can change following an
+ * update, we need to retrieve fresh info instead of stale information.
+ */
+ reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+ reg.a1 = image->fw_seq_id;
+ arm_smccc_1_2_invoke(®, ®);
+ if (reg.a0 == LFA_SUCCESS) {
+ if (reg.a5 != 0 && image->activation_pending) {
+ u32 maj, min;
+
+ image->pending_version = reg.a5;
+ maj = reg.a5 >> 32;
+ min = reg.a5 & 0xffffffff;
+
+ return sysfs_emit(buf, "%u.%u\n", maj, min);
+ }
+ }
+
+ return sysfs_emit(buf, "N/A\n");
+}
+
+static ssize_t activate_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ int ret;
+
+ ret = prime_fw_image(image);
+ if (ret)
+ return -ECANCELED;
+
+ ret = activate_fw_image(image);
+ if (ret)
+ return -ECANCELED;
+
+ pr_info("%s: successfully activated\n", get_image_name(image));
+
+ return count;
+}
+
+static ssize_t cancel_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ int ret;
+
+ ret = lfa_cancel(image);
+ if (ret != 0)
+ return ret;
+
+ return count;
+}
+
+static struct kobj_attribute image_attrs_group[LFA_ATTR_NR_IMAGES] = {
+ [LFA_ATTR_NAME] = __ATTR_RO(name),
+ [LFA_ATTR_CURRENT_VERSION] = __ATTR_RO(current_version),
+ [LFA_ATTR_PENDING_VERSION] = __ATTR_RO(pending_version),
+ [LFA_ATTR_ACT_CAPABLE] = __ATTR_RO(activation_capable),
+ [LFA_ATTR_ACT_PENDING] = __ATTR_RO(activation_pending),
+ [LFA_ATTR_MAY_RESET_CPU] = __ATTR_RO(may_reset_cpu),
+ [LFA_ATTR_CPU_RENDEZVOUS] = __ATTR_RO(cpu_rendezvous),
+ [LFA_ATTR_FORCE_CPU_RENDEZVOUS] = __ATTR_RW(force_cpu_rendezvous),
+ [LFA_ATTR_ACTIVATE] = __ATTR_WO(activate),
+ [LFA_ATTR_CANCEL] = __ATTR_WO(cancel)
+};
+
+static void init_image_default_attrs(void)
+{
+ for (int i = 0; i < LFA_ATTR_NR_IMAGES; i++)
+ image_default_attrs[i] = &image_attrs_group[i].attr;
+ image_default_attrs[LFA_ATTR_NR_IMAGES] = NULL;
+}
+
+static void clean_fw_images_tree(void)
+{
+ struct kobject *kobj, *tmp;
+ struct list_head images_to_delete;
+
+ INIT_LIST_HEAD(&images_to_delete);
+
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry_safe(kobj, tmp, &lfa_kset->list, entry) {
+ list_move_tail(&kobj->entry, &images_to_delete);
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
+ list_for_each_entry_safe(kobj, tmp, &images_to_delete, entry) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ delete_fw_image_node(image);
+ }
+}
+
+static int update_fw_image_node(char *fw_uuid, int seq_id,
+ u32 image_flags, u64 reg_current_ver,
+ u64 reg_pending_ver)
+{
+ const char *image_name = "";
+ struct fw_image *image;
+ struct kobject *kobj;
+ int i;
+
+ /*
+ * If a fw_image is already in the images list then we just update
+ * its flags and seq_id instead of trying to recreate it.
+ */
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry(kobj, &lfa_kset->list, entry) {
+ if (!strcmp(kobject_name(kobj), fw_uuid)) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ set_image_flags(image, seq_id, image_flags,
+ reg_current_ver, reg_pending_ver);
+ spin_unlock(&lfa_kset->list_lock);
+
+ return 0;
+ }
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
+ image = kzalloc_obj(*image);
+ if (!image)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(fw_images_uuids); i++) {
+ if (!strcmp(fw_images_uuids[i].uuid, fw_uuid))
+ image_name = fw_images_uuids[i].name;
+ }
+
+ image->kobj.kset = lfa_kset;
+ image->image_name = image_name;
+ image->cpu_rendezvous_forced = true;
+ set_image_flags(image, seq_id, image_flags, reg_current_ver,
+ reg_pending_ver);
+ if (kobject_init_and_add(&image->kobj, &image_ktype, NULL,
+ "%s", fw_uuid)) {
+ kobject_put(&image->kobj);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int update_fw_images_tree(void)
+{
+ struct arm_smccc_1_2_regs reg = { 0 }, res;
+ struct uuid_regs image_uuid;
+ char image_id_str[40];
+ int ret, num_of_components;
+
+ num_of_components = get_nr_lfa_components();
+ if (num_of_components <= 0) {
+ pr_err("Error getting number of LFA components\n");
+ return -ENODEV;
+ }
+
+ reg.a0 = LFA_1_0_FN_GET_INVENTORY;
+ for (int i = 0; i < num_of_components; i++) {
+ reg.a1 = i; /* fw_seq_id to be queried */
+ arm_smccc_1_2_invoke(®, &res);
+ if (res.a0 == LFA_SUCCESS) {
+ image_uuid.uuid_lo = res.a1;
+ image_uuid.uuid_hi = res.a2;
+
+ snprintf(image_id_str, sizeof(image_id_str), "%pUb",
+ &image_uuid);
+ ret = update_fw_image_node(image_id_str, i, res.a3,
+ res.a4, res.a5);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __init lfa_init(void)
+{
+ struct arm_smccc_1_2_regs reg = { 0 };
+ int err;
+
+ reg.a0 = LFA_1_0_FN_GET_VERSION;
+ arm_smccc_1_2_invoke(®, ®);
+ if (reg.a0 == -LFA_NOT_SUPPORTED) {
+ pr_info("Live Firmware activation: no firmware agent found\n");
+ return -ENODEV;
+ }
+
+ pr_info("Live Firmware Activation: detected v%ld.%ld\n",
+ reg.a0 >> 16, reg.a0 & 0xffff);
+
+ fw_images_update_wq = alloc_workqueue("fw_images_update_wq",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!fw_images_update_wq) {
+ pr_err("Live Firmware Activation: Failed to allocate workqueue.\n");
+
+ return -ENOMEM;
+ }
+ INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
+
+ init_image_default_attrs();
+ lfa_kset = kset_create_and_add("lfa", NULL, firmware_kobj);
+ if (!lfa_kset)
+ return -ENOMEM;
+
+ err = update_fw_images_tree();
+ if (err != 0) {
+ kset_unregister(lfa_kset);
+ destroy_workqueue(fw_images_update_wq);
+ }
+
+ return err;
+}
+module_init(lfa_init);
+
+static void __exit lfa_exit(void)
+{
+ flush_workqueue(fw_images_update_wq);
+ destroy_workqueue(fw_images_update_wq);
+ clean_fw_images_tree();
+ kset_unregister(lfa_kset);
+}
+module_exit(lfa_exit);
+
+MODULE_DESCRIPTION("ARM Live Firmware Activation (LFA)");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 3/8] firmware: smccc: lfa: Move image rescanning
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
2026-03-17 10:33 ` [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding Andre Przywara
2026-03-17 10:33 ` [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA) Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 4/8] firmware: smccc: lfa: Add timeout and trigger watchdog Andre Przywara
` (5 subsequent siblings)
8 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
From: Vedashree Vidwans <vvidwans@nvidia.com>
After an image activation, the list of firmware images might change, so
we have to re-iterate them through the SMC interface.
Move the corresponding code from the activate_fw_image() function into
update_fw_images_tree(), where it could be reused more easily, for
instance when triggered by an interrupt.
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
[Andre: split off from another patch, rebased]
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 46 ++++++++++++++++-----------------
1 file changed, 22 insertions(+), 24 deletions(-)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 284b7c18d3d0..4831abf2b60e 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -310,7 +310,6 @@ static int call_lfa_activate(void *data)
static int activate_fw_image(struct fw_image *image)
{
- struct kobject *kobj;
int ret;
retry:
@@ -320,31 +319,8 @@ static int activate_fw_image(struct fw_image *image)
ret = call_lfa_activate(image);
if (!ret) {
- /*
- * Invalidate fw_seq_ids (-1) for all images as the seq_ids
- * and the number of firmware images in the LFA agent may
- * change after a successful activation attempt.
- * Negate all image flags as well.
- */
- spin_lock(&lfa_kset->list_lock);
- list_for_each_entry(kobj, &lfa_kset->list, entry) {
- struct fw_image *image = kobj_to_fw_image(kobj);
-
- set_image_flags(image, -1, 0b1000, 0, 0);
- }
- spin_unlock(&lfa_kset->list_lock);
-
update_fw_images_tree();
- /*
- * Removing non-valid image directories at the end of an
- * activation.
- * We can't remove the sysfs attributes while in the respective
- * _store() handler, so have to postpone the list removal to a
- * workqueue.
- */
- queue_work(fw_images_update_wq, &fw_images_update_work);
-
return 0;
}
@@ -640,6 +616,7 @@ static int update_fw_images_tree(void)
{
struct arm_smccc_1_2_regs reg = { 0 }, res;
struct uuid_regs image_uuid;
+ struct kobject *kobj;
char image_id_str[40];
int ret, num_of_components;
@@ -649,6 +626,19 @@ static int update_fw_images_tree(void)
return -ENODEV;
}
+ /*
+ * Invalidate fw_seq_ids (-1) for all images as the seq_ids and the
+ * number of firmware images in the LFA agent may change after a
+ * successful activation attempt. Negate all image flags as well.
+ */
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry(kobj, &lfa_kset->list, entry) {
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ set_image_flags(image, -1, 0b1000, 0, 0);
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
reg.a0 = LFA_1_0_FN_GET_INVENTORY;
for (int i = 0; i < num_of_components; i++) {
reg.a1 = i; /* fw_seq_id to be queried */
@@ -666,6 +656,14 @@ static int update_fw_images_tree(void)
}
}
+ /*
+ * Removing non-valid image directories at the end of an activation.
+ * We can't remove the sysfs attributes while in the respective
+ * _store() handler, so have to postpone the list removal to a
+ * workqueue.
+ */
+ queue_work(fw_images_update_wq, &fw_images_update_work);
+
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 4/8] firmware: smccc: lfa: Add timeout and trigger watchdog
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (2 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 3/8] firmware: smccc: lfa: Move image rescanning Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 5/8] firmware: smccc: lfa: Register ACPI notification Andre Przywara
` (4 subsequent siblings)
8 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
From: Vedashree Vidwans <vvidwans@nvidia.com>
Enhance PRIME/ACTIVATION functions to touch watchdog and implement
timeout mechanism. This update ensures that any potential hangs are
detected promptly and that the LFA process is allocated sufficient
execution time before the watchdog timer expires. These changes improve
overall system reliability by reducing the risk of undetected process
stalls and unexpected watchdog resets.
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 43 ++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 4831abf2b60e..d1b5cd29b8a0 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -5,11 +5,14 @@
#include <linux/arm-smccc.h>
#include <linux/array_size.h>
+#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kobject.h>
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/nmi.h>
#include <linux/psci.h>
#include <linux/stop_machine.h>
#include <linux/string.h>
@@ -38,6 +41,11 @@
#define LFA_PRIME_CALL_AGAIN BIT(0)
#define LFA_ACTIVATE_CALL_AGAIN BIT(0)
+#define LFA_PRIME_BUDGET_MS 30000 /* 30s cap */
+#define LFA_PRIME_DELAY_MS 10 /* 10ms between polls */
+#define LFA_ACTIVATE_BUDGET_MS 10000 /* 10s cap */
+#define LFA_ACTIVATE_DELAY_MS 10 /* 10ms between polls */
+
/* LFA return values */
#define LFA_SUCCESS 0
#define LFA_NOT_SUPPORTED 1
@@ -287,6 +295,7 @@ static int call_lfa_activate(void *data)
struct fw_image *image = data;
struct arm_smccc_1_2_regs reg = { 0 }, res;
+ touch_nmi_watchdog();
reg.a0 = LFA_1_0_FN_ACTIVATE;
reg.a1 = image->fw_seq_id;
/*
@@ -310,6 +319,7 @@ static int call_lfa_activate(void *data)
static int activate_fw_image(struct fw_image *image)
{
+ ktime_t end = ktime_add_ms(ktime_get(), LFA_ACTIVATE_BUDGET_MS);
int ret;
retry:
@@ -324,8 +334,15 @@ static int activate_fw_image(struct fw_image *image)
return 0;
}
- if (ret == -LFA_CALL_AGAIN)
- goto retry;
+ if (ret == -LFA_CALL_AGAIN) {
+ /* SMC returned with call_again flag set */
+ if (ktime_before(ktime_get(), end)) {
+ msleep_interruptible(LFA_ACTIVATE_DELAY_MS);
+ goto retry;
+ }
+
+ ret = -LFA_TIMED_OUT;
+ }
lfa_cancel(image);
@@ -338,6 +355,8 @@ static int activate_fw_image(struct fw_image *image)
static int prime_fw_image(struct fw_image *image)
{
struct arm_smccc_1_2_regs reg = { 0 }, res;
+ ktime_t end = ktime_add_ms(ktime_get(), LFA_PRIME_BUDGET_MS);
+ int ret;
if (image->may_reset_cpu) {
pr_err("CPU reset not supported by kernel driver\n");
@@ -345,6 +364,8 @@ static int prime_fw_image(struct fw_image *image)
return -EINVAL;
}
+ touch_nmi_watchdog();
+
reg.a0 = LFA_1_0_FN_PRIME;
retry:
/*
@@ -363,8 +384,22 @@ static int prime_fw_image(struct fw_image *image)
return res.a0;
}
- if (res.a1 & LFA_PRIME_CALL_AGAIN)
- goto retry;
+ if (res.a1 & LFA_PRIME_CALL_AGAIN) {
+ /* SMC returned with call_again flag set */
+ if (ktime_before(ktime_get(), end)) {
+ msleep_interruptible(LFA_PRIME_DELAY_MS);
+ goto retry;
+ }
+
+ pr_err("LFA_PRIME for image %s timed out",
+ get_image_name(image));
+
+ ret = lfa_cancel(image);
+ if (ret != 0)
+ return ret;
+
+ return -ETIMEDOUT;
+ }
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 5/8] firmware: smccc: lfa: Register ACPI notification
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (3 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 4/8] firmware: smccc: lfa: Add timeout and trigger watchdog Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file Andre Przywara
` (3 subsequent siblings)
8 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
From: Vedashree Vidwans <vvidwans@nvidia.com>
The Arm LFA spec describes an ACPI notification mechanism, where the
platform (firmware) can notify an LFA client about newly available
firmware imag updates ("pending images" in LFA terms).
Add a faux device after discovering the existence of an LFA agent via
the SMCCC discovery mechnism, and use that device to check for the ACPI
notification description. Register this when one is provided.
The notification just conveys the fact that at least one firmware image
has now a pending update, it doesn't say which, also there could be more
than one pending. Loop through all images to find every which needs to
be activated, and trigger the activation. We need to do this is a loop,
since an activation might change the number and the status of available
images.
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
[Andre: convert from platform driver to faux device]
Signed-off-by: Andre Przywara <andre.przywar@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 147 ++++++++++++++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index d1b5cd29b8a0..f20ea45cdbd9 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -3,11 +3,14 @@
* Copyright (C) 2025 Arm Limited
*/
+#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/array_size.h>
#include <linux/delay.h>
+#include <linux/device/faux.h>
#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/ktime.h>
#include <linux/list.h>
@@ -17,11 +20,13 @@
#include <linux/stop_machine.h>
#include <linux/string.h>
#include <linux/sysfs.h>
+#include <linux/types.h>
#include <linux/uuid.h>
#include <linux/workqueue.h>
#include <uapi/linux/psci.h>
+#define DRIVER_NAME "ARM_LFA"
#undef pr_fmt
#define pr_fmt(fmt) "Arm LFA: " fmt
@@ -702,6 +707,139 @@ static int update_fw_images_tree(void)
return 0;
}
+/*
+ * Go through all FW images in a loop and trigger activation
+ * of all activatible and pending images.
+ * We have to restart enumeration after every triggered activation,
+ * since the firmware images might have changed during the activation.
+ */
+static int activate_pending_image(void)
+{
+ struct kobject *kobj;
+ bool found_pending = false;
+ struct fw_image *image;
+ int ret;
+
+ spin_lock(&lfa_kset->list_lock);
+ list_for_each_entry(kobj, &lfa_kset->list, entry) {
+ image = kobj_to_fw_image(kobj);
+
+ if (image->fw_seq_id == -1)
+ continue; /* Invalid FW component */
+
+ update_fw_image_pending(image);
+ if (image->activation_capable && image->activation_pending) {
+ found_pending = true;
+ break;
+ }
+ }
+ spin_unlock(&lfa_kset->list_lock);
+
+ if (!found_pending)
+ return -ENOENT;
+
+ ret = prime_fw_image(image);
+ if (ret)
+ return ret;
+
+ ret = activate_fw_image(image);
+ if (ret)
+ return ret;
+
+ pr_info("%s: automatic activation succeeded\n", get_image_name(image));
+
+ return 0;
+}
+
+#ifdef CONFIG_ACPI
+static void lfa_acpi_notify_handler(acpi_handle handle, u32 event, void *data)
+{
+ int ret;
+
+ while (!(ret = activate_pending_image()))
+ ;
+
+ if (ret != -ENOENT)
+ pr_warn("notified image activation failed: %d\n", ret);
+}
+
+static int lfa_register_acpi(struct device *dev)
+{
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
+ acpi_status status;
+
+ acpi_dev = acpi_dev_get_first_match_dev("ARML0003", NULL, -1);
+ if (!acpi_dev)
+ return -ENODEV;
+ handle = acpi_device_handle(acpi_dev);
+ if (!handle) {
+ acpi_dev_put(acpi_dev);
+ return -ENODEV;
+ }
+
+ /* Register notify handler that indicates LFA updates are available */
+ status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
+ lfa_acpi_notify_handler, NULL);
+ if (ACPI_FAILURE(status)) {
+ acpi_dev_put(acpi_dev);
+ return -EIO;
+ }
+
+ ACPI_COMPANION_SET(dev, acpi_dev);
+
+ return 0;
+}
+
+static void lfa_remove_acpi(struct device *dev)
+{
+ struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
+ acpi_handle handle = acpi_device_handle(acpi_dev);
+
+ if (handle)
+ acpi_remove_notify_handler(handle,
+ ACPI_DEVICE_NOTIFY,
+ lfa_acpi_notify_handler);
+ acpi_dev_put(acpi_dev);
+}
+#else /* !CONFIG_ACPI */
+static int lfa_register_acpi(struct device *dev)
+{
+ return -ENODEV;
+}
+
+static void lfa_remove_acpi(struct device *dev)
+{
+}
+#endif
+
+static int lfa_faux_probe(struct faux_device *fdev)
+{
+ int ret;
+
+ if (!acpi_disabled) {
+ ret = lfa_register_acpi(&fdev->dev);
+ if (ret != -ENODEV) {
+ if (!ret)
+ pr_info("registered LFA ACPI notification\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void lfa_faux_remove(struct faux_device *fdev)
+{
+ lfa_remove_acpi(&fdev->dev);
+}
+
+static struct faux_device *lfa_dev;
+static struct faux_device_ops lfa_device_ops = {
+ .probe = lfa_faux_probe,
+ .remove = lfa_faux_remove,
+};
+
static int __init lfa_init(void)
{
struct arm_smccc_1_2_regs reg = { 0 };
@@ -731,6 +869,14 @@ static int __init lfa_init(void)
if (!lfa_kset)
return -ENOMEM;
+ /*
+ * This faux device is just used for the optional notification
+ * mechanism, to register the ACPI notification or interrupt.
+ * If the firmware tables do not contain this information, the
+ * driver will still work.
+ */
+ lfa_dev = faux_device_create("arm-lfa", NULL, &lfa_device_ops);
+
err = update_fw_images_tree();
if (err != 0) {
kset_unregister(lfa_kset);
@@ -747,6 +893,7 @@ static void __exit lfa_exit(void)
destroy_workqueue(fw_images_update_wq);
clean_fw_images_tree();
kset_unregister(lfa_kset);
+ faux_device_destroy(lfa_dev);
}
module_exit(lfa_exit);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (4 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 5/8] firmware: smccc: lfa: Register ACPI notification Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-18 8:05 ` Krzysztof Kozlowski
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
` (2 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
The Arm LFA spec places control over the actual activation process in
the hands of the non-secure host OS. An platform initiated interrupt or
notification signals the availability of an updateable firmware image,
but does not necessarily need to trigger it automatically.
Add a sysfs control file that guards such automatic activation. If an
administrator wants to allow automatic platform initiated updates, they
can activate that by echoing a "1" into the auto_activate file in the
respective sysfs directory. Any incoming notification would then result
in the activation triggered.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 34 ++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index f20ea45cdbd9..5dc531e462eb 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -101,6 +101,7 @@ enum image_attr_names {
LFA_ATTR_FORCE_CPU_RENDEZVOUS,
LFA_ATTR_ACTIVATE,
LFA_ATTR_CANCEL,
+ LFA_ATTR_AUTO_ACTIVATE,
LFA_ATTR_NR_IMAGES
};
@@ -115,6 +116,7 @@ struct fw_image {
bool may_reset_cpu;
bool cpu_rendezvous;
bool cpu_rendezvous_forced;
+ bool auto_activate;
struct kobj_attribute image_attrs[LFA_ATTR_NR_IMAGES];
};
@@ -561,6 +563,28 @@ static ssize_t cancel_store(struct kobject *kobj, struct kobj_attribute *attr,
return count;
}
+static ssize_t auto_activate_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+ int ret;
+
+ ret = kstrtobool(buf, &image->auto_activate);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t auto_activate_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct fw_image *image = kobj_to_fw_image(kobj);
+
+ return sysfs_emit(buf, "%d\n", image->auto_activate);
+}
+
static struct kobj_attribute image_attrs_group[LFA_ATTR_NR_IMAGES] = {
[LFA_ATTR_NAME] = __ATTR_RO(name),
[LFA_ATTR_CURRENT_VERSION] = __ATTR_RO(current_version),
@@ -571,7 +595,8 @@ static struct kobj_attribute image_attrs_group[LFA_ATTR_NR_IMAGES] = {
[LFA_ATTR_CPU_RENDEZVOUS] = __ATTR_RO(cpu_rendezvous),
[LFA_ATTR_FORCE_CPU_RENDEZVOUS] = __ATTR_RW(force_cpu_rendezvous),
[LFA_ATTR_ACTIVATE] = __ATTR_WO(activate),
- [LFA_ATTR_CANCEL] = __ATTR_WO(cancel)
+ [LFA_ATTR_CANCEL] = __ATTR_WO(cancel),
+ [LFA_ATTR_AUTO_ACTIVATE] = __ATTR_RW(auto_activate),
};
static void init_image_default_attrs(void)
@@ -640,6 +665,7 @@ static int update_fw_image_node(char *fw_uuid, int seq_id,
image->kobj.kset = lfa_kset;
image->image_name = image_name;
image->cpu_rendezvous_forced = true;
+ image->auto_activate = false;
set_image_flags(image, seq_id, image_flags, reg_current_ver,
reg_pending_ver);
if (kobject_init_and_add(&image->kobj, &image_ktype, NULL,
@@ -709,7 +735,8 @@ static int update_fw_images_tree(void)
/*
* Go through all FW images in a loop and trigger activation
- * of all activatible and pending images.
+ * of all activatible and pending images, but only if automatic
+ * activation for that image is allowed.
* We have to restart enumeration after every triggered activation,
* since the firmware images might have changed during the activation.
*/
@@ -728,7 +755,8 @@ static int activate_pending_image(void)
continue; /* Invalid FW component */
update_fw_image_pending(image);
- if (image->activation_capable && image->activation_pending) {
+ if (image->activation_capable && image->activation_pending &&
+ image->auto_activate) {
found_pending = true;
break;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (5 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-18 8:14 ` Krzysztof Kozlowski
` (3 more replies)
2026-03-17 10:33 ` [PATCH v2 8/8] firmware: smccc: lfa: introduce SMC access lock Andre Przywara
2026-03-18 8:00 ` [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Krzysztof Kozlowski
8 siblings, 4 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, linux-kernel,
vwadekar, Trilok Soni, devicetree, Nirmoy Das,
Krzysztof Kozlowski, linux-arm-kernel
The Arm Live Firmware Activation spec describes an asynchronous
notification mechanism, where the platform can notify the host OS about
newly pending image updates.
In the absence of the ACPI notification mechanism also a simple
devicetree node can describe an interrupt.
Add code to find the respective DT node and register the specified
interrupt, to trigger the activation if needed.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 45 +++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index 5dc531e462eb..ecd056901b8d 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -16,6 +16,8 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/nmi.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/psci.h>
#include <linux/stop_machine.h>
#include <linux/string.h>
@@ -841,6 +843,43 @@ static void lfa_remove_acpi(struct device *dev)
}
#endif
+static irqreturn_t lfa_irq_handler(int irq, void *dev_id)
+{
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t lfa_irq_handler_thread(int irq, void *dev_id)
+{
+ int ret;
+
+ while (!(ret = activate_pending_image()))
+ ;
+
+ if (ret != -ENOENT)
+ pr_warn("notified image activation failed: %d\n", ret);
+
+ return IRQ_HANDLED;
+}
+
+static int lfa_register_dt(struct device *dev)
+{
+ struct device_node *np;
+ unsigned int irq;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,lfa");
+ if (!np)
+ return -ENODEV;
+
+ irq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
+ if (!irq)
+ return -ENODEV;
+
+ return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
+ lfa_irq_handler_thread,
+ IRQF_COND_ONESHOT, NULL, NULL);
+}
+
static int lfa_faux_probe(struct faux_device *fdev)
{
int ret;
@@ -854,6 +893,12 @@ static int lfa_faux_probe(struct faux_device *fdev)
}
}
+ ret = lfa_register_dt(&fdev->dev);
+ if (!ret)
+ pr_info("registered LFA DT notification interrupt\n");
+ if (ret != -ENODEV)
+ return ret;
+
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 8/8] firmware: smccc: lfa: introduce SMC access lock
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (6 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
@ 2026-03-17 10:33 ` Andre Przywara
2026-03-18 8:00 ` [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Krzysztof Kozlowski
8 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-17 10:33 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: vsethi, Salman Nabi, linux-kernel, vwadekar, Trilok Soni,
Nirmoy Das, linux-arm-kernel
After a successful live activation, the list of firmware images might
change, which also affects the sequence IDs. We store the sequence
ID in a data structure and connect it to its GUID, which is the
identifier used to access certain image properties from userland.
When an activation is happening, the sequence ID associations might
change at any point, so we must be sure to not use any previously
learned sequence ID during this time.
Protect the association between a sequence ID and a firmware image
(its GUID, really) by a reader/writer lock. In this case it's a R/W
semaphore, so it can sleep and we can hold it for longer, also
concurrent SMC calls are not blocked on each other, it's just an
activation that blocks calls.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/firmware/smccc/lfa_fw.c | 38 +++++++++++++++++++++++++++++++--
1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index ecd056901b8d..663ba79f0713 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/psci.h>
+#include <linux/rwsem.h>
#include <linux/stop_machine.h>
#include <linux/string.h>
#include <linux/sysfs.h>
@@ -157,6 +158,16 @@ static struct workqueue_struct *fw_images_update_wq;
static struct work_struct fw_images_update_work;
static struct attribute *image_default_attrs[LFA_ATTR_NR_IMAGES + 1];
+/*
+ * A successful image activation might change the number of available images,
+ * leading to a re-order and thus re-assignment of the sequence IDs.
+ * The lock protects the connection between a firmware image (through its
+ * user visible UUID) and the sequence IDs. Anyone doing an SMC call with
+ * a sequence ID needs to take the readers lock. Doing an activation requires
+ * the writer lock, as that process might change the assocications.
+ */
+struct rw_semaphore smc_lock;
+
static const struct attribute_group image_attr_group = {
.attrs = image_default_attrs,
};
@@ -253,6 +264,7 @@ static unsigned long get_nr_lfa_components(void)
reg.a0 = LFA_1_0_FN_GET_INFO;
reg.a1 = 0; /* lfa_info_selector = 0 */
+ /* No need for the smc_lock, since no sequence IDs are involved. */
arm_smccc_1_2_invoke(®, ®);
if (reg.a0 != LFA_SUCCESS)
return reg.a0;
@@ -265,9 +277,11 @@ static int lfa_cancel(void *data)
struct fw_image *image = data;
struct arm_smccc_1_2_regs reg = { 0 };
+ down_read(&smc_lock);
reg.a0 = LFA_1_0_FN_CANCEL;
reg.a1 = image->fw_seq_id;
arm_smccc_1_2_invoke(®, ®);
+ up_read(&smc_lock);
/*
* When firmware activation is called with "skip_cpu_rendezvous=1",
@@ -332,6 +346,7 @@ static int activate_fw_image(struct fw_image *image)
int ret;
retry:
+ down_write(&smc_lock);
if (image->cpu_rendezvous_forced || image->cpu_rendezvous)
ret = stop_machine(call_lfa_activate, image, cpu_online_mask);
else
@@ -339,10 +354,13 @@ static int activate_fw_image(struct fw_image *image)
if (!ret) {
update_fw_images_tree();
+ up_write(&smc_lock);
return 0;
}
+ up_write(&smc_lock);
+
if (ret == -LFA_CALL_AGAIN) {
/* SMC returned with call_again flag set */
if (ktime_before(ktime_get(), end)) {
@@ -383,8 +401,11 @@ static int prime_fw_image(struct fw_image *image)
* be called again.
* reg.a1 will become 0 once the prime process completes.
*/
+ down_read(&smc_lock);
reg.a1 = image->fw_seq_id;
arm_smccc_1_2_invoke(®, &res);
+ up_read(&smc_lock);
+
if ((long)res.a0 < 0) {
pr_err("LFA_PRIME for image %s failed: %s\n",
get_image_name(image),
@@ -429,7 +450,7 @@ static ssize_t activation_capable_show(struct kobject *kobj,
return sysfs_emit(buf, "%d\n", image->activation_capable);
}
-static void update_fw_image_pending(struct fw_image *image)
+static void _update_fw_image_pending(struct fw_image *image)
{
struct arm_smccc_1_2_regs reg = { 0 };
@@ -441,6 +462,13 @@ static void update_fw_image_pending(struct fw_image *image)
image->activation_pending = !!(reg.a3 & BIT(1));
}
+static void update_fw_image_pending(struct fw_image *image)
+{
+ down_read(&smc_lock);
+ _update_fw_image_pending(image);
+ up_read(&smc_lock);
+}
+
static ssize_t activation_pending_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -515,9 +543,11 @@ static ssize_t pending_version_show(struct kobject *kobj,
* Similar to activation pending, this value can change following an
* update, we need to retrieve fresh info instead of stale information.
*/
+ down_read(&smc_lock);
reg.a0 = LFA_1_0_FN_GET_INVENTORY;
reg.a1 = image->fw_seq_id;
arm_smccc_1_2_invoke(®, ®);
+ up_read(&smc_lock);
if (reg.a0 == LFA_SUCCESS) {
if (reg.a5 != 0 && image->activation_pending) {
u32 maj, min;
@@ -749,6 +779,7 @@ static int activate_pending_image(void)
struct fw_image *image;
int ret;
+ down_read(&smc_lock);
spin_lock(&lfa_kset->list_lock);
list_for_each_entry(kobj, &lfa_kset->list, entry) {
image = kobj_to_fw_image(kobj);
@@ -756,7 +787,7 @@ static int activate_pending_image(void)
if (image->fw_seq_id == -1)
continue; /* Invalid FW component */
- update_fw_image_pending(image);
+ _update_fw_image_pending(image);
if (image->activation_capable && image->activation_pending &&
image->auto_activate) {
found_pending = true;
@@ -764,6 +795,7 @@ static int activate_pending_image(void)
}
}
spin_unlock(&lfa_kset->list_lock);
+ up_read(&smc_lock);
if (!found_pending)
return -ENOENT;
@@ -950,6 +982,8 @@ static int __init lfa_init(void)
*/
lfa_dev = faux_device_create("arm-lfa", NULL, &lfa_device_ops);
+ init_rwsem(&smc_lock);
+
err = update_fw_images_tree();
if (err != 0) {
kset_unregister(lfa_kset);
--
2.43.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
` (7 preceding siblings ...)
2026-03-17 10:33 ` [PATCH v2 8/8] firmware: smccc: lfa: introduce SMC access lock Andre Przywara
@ 2026-03-18 8:00 ` Krzysztof Kozlowski
8 siblings, 0 replies; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:00 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Rob Herring,
Lorenzo Pieralisi, linux-kernel, vwadekar, Sudeep Holla,
devicetree, Conor Dooley, vsethi, Nirmoy Das, Krzysztof Kozlowski,
linux-arm-kernel
On Tue, Mar 17, 2026 at 11:33:26AM +0100, Andre Przywara wrote:
> Changelog v1 .. v2:
> - restrict build to arm64 (the LFA spec only supports AArch64)
> - rename and extend central data structure to fw_image
> - use separate GPR register sets for some SMC calls
> - provide wrapper for error messages to prevent out-of-bound access
> - return GUID in the "name" sysfs file when image is unknown
> - fix wrong attribute in pending version number show function
> - add missing include files and order them properly
> - fix memory leaks in error cleanup paths
> - handle lifetime using embedded kobjects and a kset
> - drop global lfa_lock, use kset list lock and kobject refcount instead
> - add DT binding documentation
> - add timeout and watchdog re-arming (contributed by Veda)
> - relax timeout period and do not block while waiting
> - register ACPI notification (contributed by Veda) and DT interrupt
> - refactor ACPI notification code to allow sharing with DT code
> - use faux device instead of platform driver
> - add auto_activate file to control automatic activation
> - introduce rwsem mutex to prevent using stale sequence ID
> - use labels and goto instead of infinite loop when retrying activation
> - initialise workqueue only once (thanks to Nirmoy)
> - various cleanups on reported messages and code formatting
> - rebase on top of v7.0-rc1
>
> Changelog RFC .. v1:
Please start using b4 for developing patches. RFC is v1. RFCv2 is v2.
Whatever next is always + 1. Otherwise please share how v1 and RFC can be
easily compared with b4 diff...
> - Updated SMCCC version 1.1 to 1.2 per the LFA specification requirement.
> - Changed "image_props" array to a linked list to support the dynamic
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding
2026-03-17 10:33 ` [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding Andre Przywara
@ 2026-03-18 8:04 ` Krzysztof Kozlowski
2026-03-18 16:00 ` Andre Przywara
0 siblings, 1 reply; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:04 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Rob Herring, Conor Dooley, devicetree,
Lorenzo Pieralisi, Trilok Soni, Salman Nabi, vwadekar,
linux-kernel, Sudeep Holla, vsethi, Krzysztof Kozlowski,
Nirmoy Das, linux-arm-kernel
On Tue, Mar 17, 2026 at 11:33:27AM +0100, Andre Przywara wrote:
> The Arm Live Firmware Activation spec [1] describes updating firmware
A nit, subject: drop second/last, redundant "binding". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
> images during runtime, without requiring a reboot. Update images might
> be deployed out-of-band, for instance via a BMC, in this case the OS
> needs to be notified about the availability of a new image.
>
> This binding describes an interrupt that could be triggered by the
Describe hardware/firmware, not the binding.
> platform, to notify about any changes.
>
> [1] https://developer.arm.com/documentation/den0147/latest/
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> .../devicetree/bindings/arm/arm,lfa.yaml | 45 +++++++++++++++++++
> 1 file changed, 45 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/arm,lfa.yaml
>
> diff --git a/Documentation/devicetree/bindings/arm/arm,lfa.yaml b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
> new file mode 100644
> index 000000000000..92f0564fd672
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/arm,lfa.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Arm Live Firmware Activation (LFA)
> +
> +maintainers:
> + - Andre Przywara <andre.przywara@arm.com>
> + - Sudeep Holla <sudeep.holla@arm.com>
> +
> +description:
> + The Arm Live Firmware Activation (LFA) specification [1] describes a
> + firmware interface to activate an updated firmware at runtime, without
> + requiring a reboot. Updates might be supplied out-of-band, for instance
> + via a BMC, in which case the platform needs to notify an OS about pending
> + image updates.
> + [1] https://developer.arm.com/documentation/den0147/latest/
> +
> +properties:
> + compatible:
> + const: arm,lfa
Does specification has a version? Does it support version discovery?
> +
> + interrupts:
> + maxItems: 1
> + description: notification interrupt for changed firmware image status
> +
> +required:
> + - compatible
> + - interrupts
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> + firmware {
> + arm-lfa {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
If you cannot find a name matching your device, please check in kernel
sources for similar cases or you can grow the spec (via pull request to
DT spec repo).
arm-lfa is specific, so this could be as "fota" or "firmware-update"
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file
2026-03-17 10:33 ` [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file Andre Przywara
@ 2026-03-18 8:05 ` Krzysztof Kozlowski
0 siblings, 0 replies; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:05 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Lorenzo Pieralisi,
linux-kernel, vwadekar, Sudeep Holla, vsethi, Nirmoy Das,
linux-arm-kernel
On Tue, Mar 17, 2026 at 11:33:32AM +0100, Andre Przywara wrote:
>
> @@ -115,6 +116,7 @@ struct fw_image {
> bool may_reset_cpu;
> bool cpu_rendezvous;
> bool cpu_rendezvous_forced;
> + bool auto_activate;
> struct kobj_attribute image_attrs[LFA_ATTR_NR_IMAGES];
> };
>
> @@ -561,6 +563,28 @@ static ssize_t cancel_store(struct kobject *kobj, struct kobj_attribute *attr,
> return count;
> }
>
> +static ssize_t auto_activate_store(struct kobject *kobj,
> + struct kobj_attribute *attr,
> + const char *buf, size_t count)
Where is this ABI documented?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA)
2026-03-17 10:33 ` [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA) Andre Przywara
@ 2026-03-18 8:09 ` Krzysztof Kozlowski
2026-03-18 8:12 ` Krzysztof Kozlowski
0 siblings, 1 reply; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:09 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Lorenzo Pieralisi,
linux-kernel, vwadekar, Sudeep Holla, vsethi, Nirmoy Das,
linux-arm-kernel
On Tue, Mar 17, 2026 at 11:33:28AM +0100, Andre Przywara wrote:
> +
> +/* A list of known GUIDs, to be shown in the "name" sysfs file. */
> +static const struct fw_image_uuid {
> + const char *name;
> + const char *uuid;
> +} fw_images_uuids[] = {
> + {
> + .name = "TF-A BL31 runtime",
> + .uuid = "47d4086d-4cfe-9846-9b95-2950cbbd5a00",
> + },
> + {
> + .name = "BL33 non-secure payload",
> + .uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4",
> + },
> + {
> + .name = "TF-RMM",
> + .uuid = "6c0762a6-12f2-4b56-92cb-ba8f633606d9",
> + },
> +};
> +
> +static struct kset *lfa_kset;
> +static struct workqueue_struct *fw_images_update_wq;
> +static struct work_struct fw_images_update_work;
> +static struct attribute *image_default_attrs[LFA_ATTR_NR_IMAGES + 1];
Bunch of singletons here because (see later)...
> +
> +static const struct attribute_group image_attr_group = {
> + .attrs = image_default_attrs,
> +};
> +
> +static const struct attribute_group *image_default_groups[] = {
> + &image_attr_group,
> + NULL
> +};
> +
> +static int __init lfa_init(void)
> +{
> + struct arm_smccc_1_2_regs reg = { 0 };
> + int err;
> +
> + reg.a0 = LFA_1_0_FN_GET_VERSION;
> + arm_smccc_1_2_invoke(®, ®);
> + if (reg.a0 == -LFA_NOT_SUPPORTED) {
> + pr_info("Live Firmware activation: no firmware agent found\n");
> + return -ENODEV;
> + }
> +
> + pr_info("Live Firmware Activation: detected v%ld.%ld\n",
> + reg.a0 >> 16, reg.a0 & 0xffff);
> +
> + fw_images_update_wq = alloc_workqueue("fw_images_update_wq",
> + WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
> + if (!fw_images_update_wq) {
> + pr_err("Live Firmware Activation: Failed to allocate workqueue.\n");
> +
> + return -ENOMEM;
> + }
> + INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
> +
> + init_image_default_attrs();
> + lfa_kset = kset_create_and_add("lfa", NULL, firmware_kobj);
> + if (!lfa_kset)
> + return -ENOMEM;
> +
> + err = update_fw_images_tree();
> + if (err != 0) {
> + kset_unregister(lfa_kset);
> + destroy_workqueue(fw_images_update_wq);
> + }
> +
> + return err;
> +}
> +module_init(lfa_init);
You do not use driver model, but 199x style of modprobing and performing
actions.
I do not understand why module load is already doign anything. This
looks like misinterpretation/misuse of Linux driver model - in a way,
you don't use it all and this is like back to 199x where modprobe was
already meaning you bind drivers...
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA)
2026-03-18 8:09 ` Krzysztof Kozlowski
@ 2026-03-18 8:12 ` Krzysztof Kozlowski
2026-03-18 15:39 ` Andre Przywara
0 siblings, 1 reply; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:12 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Lorenzo Pieralisi,
linux-kernel, vwadekar, Sudeep Holla, vsethi, Nirmoy Das,
linux-arm-kernel
On 18/03/2026 09:09, Krzysztof Kozlowski wrote:
> On Tue, Mar 17, 2026 at 11:33:28AM +0100, Andre Przywara wrote:
>> +
>> +/* A list of known GUIDs, to be shown in the "name" sysfs file. */
>> +static const struct fw_image_uuid {
>> + const char *name;
>> + const char *uuid;
>> +} fw_images_uuids[] = {
>> + {
>> + .name = "TF-A BL31 runtime",
>> + .uuid = "47d4086d-4cfe-9846-9b95-2950cbbd5a00",
>> + },
>> + {
>> + .name = "BL33 non-secure payload",
>> + .uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4",
>> + },
>> + {
>> + .name = "TF-RMM",
>> + .uuid = "6c0762a6-12f2-4b56-92cb-ba8f633606d9",
>> + },
>> +};
>> +
>> +static struct kset *lfa_kset;
>> +static struct workqueue_struct *fw_images_update_wq;
>> +static struct work_struct fw_images_update_work;
>> +static struct attribute *image_default_attrs[LFA_ATTR_NR_IMAGES + 1];
>
> Bunch of singletons here because (see later)...
>
>> +
>> +static const struct attribute_group image_attr_group = {
>> + .attrs = image_default_attrs,
>> +};
>> +
>> +static const struct attribute_group *image_default_groups[] = {
>> + &image_attr_group,
>> + NULL
>> +};
>> +
>> +static int __init lfa_init(void)
>> +{
>> + struct arm_smccc_1_2_regs reg = { 0 };
>> + int err;
>> +
>> + reg.a0 = LFA_1_0_FN_GET_VERSION;
>> + arm_smccc_1_2_invoke(®, ®);
>> + if (reg.a0 == -LFA_NOT_SUPPORTED) {
>> + pr_info("Live Firmware activation: no firmware agent found\n");
>> + return -ENODEV;
>> + }
>> +
>> + pr_info("Live Firmware Activation: detected v%ld.%ld\n",
>> + reg.a0 >> 16, reg.a0 & 0xffff);
>> +
>> + fw_images_update_wq = alloc_workqueue("fw_images_update_wq",
>> + WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
>> + if (!fw_images_update_wq) {
>> + pr_err("Live Firmware Activation: Failed to allocate workqueue.\n");
>> +
>> + return -ENOMEM;
>> + }
>> + INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
>> +
>> + init_image_default_attrs();
>> + lfa_kset = kset_create_and_add("lfa", NULL, firmware_kobj);
>> + if (!lfa_kset)
>> + return -ENOMEM;
>> +
>> + err = update_fw_images_tree();
>> + if (err != 0) {
>> + kset_unregister(lfa_kset);
>> + destroy_workqueue(fw_images_update_wq);
>> + }
>> +
>> + return err;
>> +}
>> +module_init(lfa_init);
>
> You do not use driver model, but 199x style of modprobing and performing
> actions.
>
> I do not understand why module load is already doign anything. This
> looks like misinterpretation/misuse of Linux driver model - in a way,
> you don't use it all and this is like back to 199x where modprobe was
> already meaning you bind drivers...
Although now going through further patches I found you implementing some
parts of driver model, so probably this split is just needing fix.
Modprobe must not do "arm_smccc_1_2_invoke" or any other device related
things. You only initialize your bus, just like every other bus driver
would do, but honestly this should not be a bus-like code.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
@ 2026-03-18 8:14 ` Krzysztof Kozlowski
2026-03-18 11:35 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 21+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 8:14 UTC (permalink / raw)
To: Andre Przywara
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Rob Herring,
Lorenzo Pieralisi, linux-kernel, vwadekar, Sudeep Holla,
devicetree, Conor Dooley, vsethi, Nirmoy Das, Krzysztof Kozlowski,
linux-arm-kernel
On Tue, Mar 17, 2026 at 11:33:33AM +0100, Andre Przywara wrote:
> + return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
> + lfa_irq_handler_thread,
> + IRQF_COND_ONESHOT, NULL, NULL);
> +}
> +
> static int lfa_faux_probe(struct faux_device *fdev)
> {
> int ret;
> @@ -854,6 +893,12 @@ static int lfa_faux_probe(struct faux_device *fdev)
> }
> }
>
> + ret = lfa_register_dt(&fdev->dev);
> + if (!ret)
> + pr_info("registered LFA DT notification interrupt\n");
Drop. Drivers must be silent on success (mentioned more than once in
coding docs).
Starting FW update would deserve a comment, but probing a device or its
resource is completely irrelevant for the user.
> + if (ret != -ENODEV)
> + return ret;
> +
> return 0;
> }
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
2026-03-18 8:14 ` Krzysztof Kozlowski
@ 2026-03-18 11:35 ` kernel test robot
2026-03-18 14:21 ` kernel test robot
2026-03-18 14:21 ` kernel test robot
3 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2026-03-18 11:35 UTC (permalink / raw)
To: Andre Przywara, Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, linux-kernel,
vwadekar, Trilok Soni, devicetree, Krzysztof Kozlowski,
oe-kbuild-all, Nirmoy Das, linux-arm-kernel
Hi Andre,
kernel test robot noticed the following build warnings:
[auto build test WARNING on robh/for-next]
[also build test WARNING on arm/for-next arm/fixes arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next shawnguo/for-next soc/for-next linus/master nferre-at91/at91-next v7.0-rc4 next-20260317]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Andre-Przywara/dt-bindings-arm-Add-Live-Firmware-Activation-binding/20260318-082717
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20260317103336.1273582-8-andre.przywara%40arm.com
patch subject: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
config: arm64-randconfig-004-20260318 (https://download.01.org/0day-ci/archive/20260318/202603181913.NFRwBsN4-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260318/202603181913.NFRwBsN4-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603181913.NFRwBsN4-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/firmware/smccc/lfa_fw.c: In function 'lfa_register_dt':
drivers/firmware/smccc/lfa_fw.c:878:16: error: implicit declaration of function 'devm_request_threaded_irq'; did you mean 'devm_request_region'? [-Werror=implicit-function-declaration]
878 | return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| devm_request_region
drivers/firmware/smccc/lfa_fw.c:880:42: error: 'IRQF_COND_ONESHOT' undeclared (first use in this function)
880 | IRQF_COND_ONESHOT, NULL, NULL);
| ^~~~~~~~~~~~~~~~~
drivers/firmware/smccc/lfa_fw.c:880:42: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/firmware/smccc/lfa_fw.c:881:1: warning: control reaches end of non-void function [-Wreturn-type]
881 | }
| ^
cc1: some warnings being treated as errors
vim +881 drivers/firmware/smccc/lfa_fw.c
863
864 static int lfa_register_dt(struct device *dev)
865 {
866 struct device_node *np;
867 unsigned int irq;
868
869 np = of_find_compatible_node(NULL, NULL, "arm,lfa");
870 if (!np)
871 return -ENODEV;
872
873 irq = irq_of_parse_and_map(np, 0);
874 of_node_put(np);
875 if (!irq)
876 return -ENODEV;
877
878 return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
879 lfa_irq_handler_thread,
880 IRQF_COND_ONESHOT, NULL, NULL);
> 881 }
882
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
2026-03-18 8:14 ` Krzysztof Kozlowski
2026-03-18 11:35 ` kernel test robot
@ 2026-03-18 14:21 ` kernel test robot
2026-03-18 14:21 ` kernel test robot
3 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2026-03-18 14:21 UTC (permalink / raw)
To: Andre Przywara, Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, llvm,
linux-kernel, vwadekar, Trilok Soni, devicetree,
Krzysztof Kozlowski, oe-kbuild-all, Nirmoy Das, linux-arm-kernel
Hi Andre,
kernel test robot noticed the following build errors:
[auto build test ERROR on robh/for-next]
[also build test ERROR on arm/for-next arm/fixes arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next shawnguo/for-next soc/for-next linus/master nferre-at91/at91-next v7.0-rc4 next-20260317]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Andre-Przywara/dt-bindings-arm-Add-Live-Firmware-Activation-binding/20260318-082717
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20260317103336.1273582-8-andre.przywara%40arm.com
patch subject: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
config: arm64-randconfig-003-20260318 (https://download.01.org/0day-ci/archive/20260318/202603182205.TOBMcP5F-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 4abb927bacf37f18f6359a41639a6d1b3bffffb5)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260318/202603182205.TOBMcP5F-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603182205.TOBMcP5F-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/firmware/smccc/lfa_fw.c:878:9: error: call to undeclared function 'devm_request_threaded_irq'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
878 | return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
| ^
>> drivers/firmware/smccc/lfa_fw.c:880:7: error: use of undeclared identifier 'IRQF_COND_ONESHOT'
880 | IRQF_COND_ONESHOT, NULL, NULL);
| ^~~~~~~~~~~~~~~~~
2 errors generated.
vim +/devm_request_threaded_irq +878 drivers/firmware/smccc/lfa_fw.c
863
864 static int lfa_register_dt(struct device *dev)
865 {
866 struct device_node *np;
867 unsigned int irq;
868
869 np = of_find_compatible_node(NULL, NULL, "arm,lfa");
870 if (!np)
871 return -ENODEV;
872
873 irq = irq_of_parse_and_map(np, 0);
874 of_node_put(np);
875 if (!irq)
876 return -ENODEV;
877
> 878 return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
879 lfa_irq_handler_thread,
> 880 IRQF_COND_ONESHOT, NULL, NULL);
881 }
882
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
` (2 preceding siblings ...)
2026-03-18 14:21 ` kernel test robot
@ 2026-03-18 14:21 ` kernel test robot
2026-03-19 12:52 ` Andre Przywara
3 siblings, 1 reply; 21+ messages in thread
From: kernel test robot @ 2026-03-18 14:21 UTC (permalink / raw)
To: Andre Przywara, Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, linux-kernel,
vwadekar, Trilok Soni, devicetree, Krzysztof Kozlowski,
oe-kbuild-all, Nirmoy Das, linux-arm-kernel
Hi Andre,
kernel test robot noticed the following build errors:
[auto build test ERROR on robh/for-next]
[also build test ERROR on arm/for-next arm/fixes arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next shawnguo/for-next soc/for-next linus/master nferre-at91/at91-next v7.0-rc4 next-20260317]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Andre-Przywara/dt-bindings-arm-Add-Live-Firmware-Activation-binding/20260318-082717
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20260317103336.1273582-8-andre.przywara%40arm.com
patch subject: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
config: arm64-randconfig-004-20260318 (https://download.01.org/0day-ci/archive/20260318/202603182202.gpyCz2RF-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260318/202603182202.gpyCz2RF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603182202.gpyCz2RF-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/firmware/smccc/lfa_fw.c: In function 'lfa_register_dt':
>> drivers/firmware/smccc/lfa_fw.c:878:16: error: implicit declaration of function 'devm_request_threaded_irq'; did you mean 'devm_request_region'? [-Werror=implicit-function-declaration]
878 | return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| devm_request_region
>> drivers/firmware/smccc/lfa_fw.c:880:42: error: 'IRQF_COND_ONESHOT' undeclared (first use in this function)
880 | IRQF_COND_ONESHOT, NULL, NULL);
| ^~~~~~~~~~~~~~~~~
drivers/firmware/smccc/lfa_fw.c:880:42: note: each undeclared identifier is reported only once for each function it appears in
drivers/firmware/smccc/lfa_fw.c:881:1: warning: control reaches end of non-void function [-Wreturn-type]
881 | }
| ^
cc1: some warnings being treated as errors
vim +878 drivers/firmware/smccc/lfa_fw.c
863
864 static int lfa_register_dt(struct device *dev)
865 {
866 struct device_node *np;
867 unsigned int irq;
868
869 np = of_find_compatible_node(NULL, NULL, "arm,lfa");
870 if (!np)
871 return -ENODEV;
872
873 irq = irq_of_parse_and_map(np, 0);
874 of_node_put(np);
875 if (!irq)
876 return -ENODEV;
877
> 878 return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
879 lfa_irq_handler_thread,
> 880 IRQF_COND_ONESHOT, NULL, NULL);
881 }
882
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA)
2026-03-18 8:12 ` Krzysztof Kozlowski
@ 2026-03-18 15:39 ` Andre Przywara
0 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-18 15:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Mark Rutland, Trilok Soni, Salman Nabi, Lorenzo Pieralisi,
linux-kernel, vwadekar, Sudeep Holla, vsethi, Nirmoy Das,
linux-arm-kernel
Hi Krzysztof,
thanks for having a look!
On 3/18/26 09:12, Krzysztof Kozlowski wrote:
> On 18/03/2026 09:09, Krzysztof Kozlowski wrote:
>> On Tue, Mar 17, 2026 at 11:33:28AM +0100, Andre Przywara wrote:
>>> +
>>> +/* A list of known GUIDs, to be shown in the "name" sysfs file. */
>>> +static const struct fw_image_uuid {
>>> + const char *name;
>>> + const char *uuid;
>>> +} fw_images_uuids[] = {
>>> + {
>>> + .name = "TF-A BL31 runtime",
>>> + .uuid = "47d4086d-4cfe-9846-9b95-2950cbbd5a00",
>>> + },
>>> + {
>>> + .name = "BL33 non-secure payload",
>>> + .uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4",
>>> + },
>>> + {
>>> + .name = "TF-RMM",
>>> + .uuid = "6c0762a6-12f2-4b56-92cb-ba8f633606d9",
>>> + },
>>> +};
>>> +
>>> +static struct kset *lfa_kset;
>>> +static struct workqueue_struct *fw_images_update_wq;
>>> +static struct work_struct fw_images_update_work;
>>> +static struct attribute *image_default_attrs[LFA_ATTR_NR_IMAGES + 1];
>>
>> Bunch of singletons here because (see later)...
>>
>>> +
>>> +static const struct attribute_group image_attr_group = {
>>> + .attrs = image_default_attrs,
>>> +};
>>> +
>>> +static const struct attribute_group *image_default_groups[] = {
>>> + &image_attr_group,
>>> + NULL
>>> +};
>>> +
>>> +static int __init lfa_init(void)
>>> +{
>>> + struct arm_smccc_1_2_regs reg = { 0 };
>>> + int err;
>>> +
>>> + reg.a0 = LFA_1_0_FN_GET_VERSION;
>>> + arm_smccc_1_2_invoke(®, ®);
>>> + if (reg.a0 == -LFA_NOT_SUPPORTED) {
>>> + pr_info("Live Firmware activation: no firmware agent found\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + pr_info("Live Firmware Activation: detected v%ld.%ld\n",
>>> + reg.a0 >> 16, reg.a0 & 0xffff);
>>> +
>>> + fw_images_update_wq = alloc_workqueue("fw_images_update_wq",
>>> + WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
>>> + if (!fw_images_update_wq) {
>>> + pr_err("Live Firmware Activation: Failed to allocate workqueue.\n");
>>> +
>>> + return -ENOMEM;
>>> + }
>>> + INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
>>> +
>>> + init_image_default_attrs();
>>> + lfa_kset = kset_create_and_add("lfa", NULL, firmware_kobj);
>>> + if (!lfa_kset)
>>> + return -ENOMEM;
>>> +
>>> + err = update_fw_images_tree();
>>> + if (err != 0) {
>>> + kset_unregister(lfa_kset);
>>> + destroy_workqueue(fw_images_update_wq);
>>> + }
>>> +
>>> + return err;
>>> +}
>>> +module_init(lfa_init);
>>
>> You do not use driver model, but 199x style of modprobing and performing
>> actions.
>>
>> I do not understand why module load is already doign anything. This
>> looks like misinterpretation/misuse of Linux driver model - in a way,
>> you don't use it all and this is like back to 199x where modprobe was
>> already meaning you bind drivers...
>
> Although now going through further patches I found you implementing some
> parts of driver model, so probably this split is just needing fix.
The discovery of the LFA service works via SMC calls, which have a safe
discovery route by just calling arm_smccc_1_2_invoke() - that function
will query the conduit and do all the necessary checks.
But yes, this looks a bit out of place, and indeed there have been
proposals to create some kind of "SMCCC bus", even though this requires
some squinting to call this a "bus". But it makes some sense in the
Linux driver model, so we probably want this.
At the moment there is smccc_trng[1], where the SMCCC code registers a
simple platform device, which is matched later in the driver. But this
seems somewhat ad-hoc and overkill as well.
I just got pointed to Aneesh's recently proposed [2] auxiliary bus
approach for SMCCC, it looks like this could be generalised for all
SMCCC users?
Sudeep, can you comment what's the latest on this front? Have there been
patches or more sketched out proposals for a proper bus already?
Cheers,
Andre
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/smccc/smccc.c#n88
[2] https://lore.kernel.org/linux-arm-kernel/yq5av7f51d8y.fsf@kernel.org/
P.S.: So yes, I was aware that putting this in module_init() was not the
neatest solution, but I didn't want to hold all the rest of the code
back until we get a better one (TM).
>
> Modprobe must not do "arm_smccc_1_2_invoke" or any other device related
> things. You only initialize your bus, just like every other bus driver
> would do, but honestly this should not be a bus-like code.
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding
2026-03-18 8:04 ` Krzysztof Kozlowski
@ 2026-03-18 16:00 ` Andre Przywara
0 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-18 16:00 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Mark Rutland, Rob Herring, Conor Dooley, devicetree,
Lorenzo Pieralisi, Trilok Soni, Salman Nabi, vwadekar,
linux-kernel, Sudeep Holla, vsethi, Krzysztof Kozlowski,
Nirmoy Das, linux-arm-kernel
Hi,
On 3/18/26 09:04, Krzysztof Kozlowski wrote:
> On Tue, Mar 17, 2026 at 11:33:27AM +0100, Andre Przywara wrote:
>> The Arm Live Firmware Activation spec [1] describes updating firmware
>
> A nit, subject: drop second/last, redundant "binding". The
> "dt-bindings" prefix is already stating that these are bindings.
> See also:
> https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
Sure, will fix.
>> images during runtime, without requiring a reboot. Update images might
>> be deployed out-of-band, for instance via a BMC, in this case the OS
>> needs to be notified about the availability of a new image.
>>
>> This binding describes an interrupt that could be triggered by the
>
> Describe hardware/firmware, not the binding.
Right, sorry, this slipped through.
>> platform, to notify about any changes.
>>
>> [1] https://developer.arm.com/documentation/den0147/latest/
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> .../devicetree/bindings/arm/arm,lfa.yaml | 45 +++++++++++++++++++
>> 1 file changed, 45 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/arm/arm,lfa.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/arm/arm,lfa.yaml b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
>> new file mode 100644
>> index 000000000000..92f0564fd672
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/arm,lfa.yaml
>> @@ -0,0 +1,45 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/arm/arm,lfa.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Arm Live Firmware Activation (LFA)
>> +
>> +maintainers:
>> + - Andre Przywara <andre.przywara@arm.com>
>> + - Sudeep Holla <sudeep.holla@arm.com>
>> +
>> +description:
>> + The Arm Live Firmware Activation (LFA) specification [1] describes a
>> + firmware interface to activate an updated firmware at runtime, without
>> + requiring a reboot. Updates might be supplied out-of-band, for instance
>> + via a BMC, in which case the platform needs to notify an OS about pending
>> + image updates.
>> + [1] https://developer.arm.com/documentation/den0147/latest/
>> +
>> +properties:
>> + compatible:
>> + const: arm,lfa
>
> Does specification has a version? Does it support version discovery?
Yes and yes. there is a mandatory LFA_GET_VERSION call, with major and
minor version.
And please note that the discovery of the firmware functionality doesn't
rely on DT (or ACPI) at all - it uses discoverable SMCCC calls instead.
We just need this DT node to convey the (optional) platform specific
interrupt number.
>> +
>> + interrupts:
>> + maxItems: 1
>> + description: notification interrupt for changed firmware image status
>> +
>> +required:
>> + - compatible
>> + - interrupts
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> + firmware {
>> + arm-lfa {
>
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> If you cannot find a name matching your device, please check in kernel
> sources for similar cases or you can grow the spec (via pull request to
> DT spec repo).
>
> arm-lfa is specific, so this could be as "fota" or "firmware-update"
OK, will try to come up with a good name.
Thanks for the review!
Cheers,
Andre
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
2026-03-18 14:21 ` kernel test robot
@ 2026-03-19 12:52 ` Andre Przywara
0 siblings, 0 replies; 21+ messages in thread
From: Andre Przywara @ 2026-03-19 12:52 UTC (permalink / raw)
To: kernel test robot, Mark Rutland, Lorenzo Pieralisi, Sudeep Holla
Cc: Conor Dooley, vsethi, Salman Nabi, Rob Herring, linux-kernel,
vwadekar, Trilok Soni, devicetree, Krzysztof Kozlowski,
oe-kbuild-all, Nirmoy Das, linux-arm-kernel
Hi,
On 3/18/26 15:21, kernel test robot wrote:
> Hi Andre,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on robh/for-next]
> [also build test ERROR on arm/for-next arm/fixes arm64/for-next/core clk/clk-next kvmarm/next rockchip/for-next shawnguo/for-next soc/for-next linus/master nferre-at91/at91-next v7.0-rc4 next-20260317]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Andre-Przywara/dt-bindings-arm-Add-Live-Firmware-Activation-binding/20260318-082717
> base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
> patch link: https://lore.kernel.org/r/20260317103336.1273582-8-andre.przywara%40arm.com
> patch subject: [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt
> config: arm64-randconfig-004-20260318 (https://download.01.org/0day-ci/archive/20260318/202603182202.gpyCz2RF-lkp@intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 12.5.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260318/202603182202.gpyCz2RF-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202603182202.gpyCz2RF-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> drivers/firmware/smccc/lfa_fw.c: In function 'lfa_register_dt':
>>> drivers/firmware/smccc/lfa_fw.c:878:16: error: implicit declaration of function 'devm_request_threaded_irq'; did you mean 'devm_request_region'? [-Werror=implicit-function-declaration]
> 878 | return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
> | ^~~~~~~~~~~~~~~~~~~~~~~~~
> | devm_request_region
>>> drivers/firmware/smccc/lfa_fw.c:880:42: error: 'IRQF_COND_ONESHOT' undeclared (first use in this function)
> 880 | IRQF_COND_ONESHOT, NULL, NULL);
> | ^~~~~~~~~~~~~~~~~
> drivers/firmware/smccc/lfa_fw.c:880:42: note: each undeclared identifier is reported only once for each function it appears in
> drivers/firmware/smccc/lfa_fw.c:881:1: warning: control reaches end of non-void function [-Wreturn-type]
> 881 | }
> | ^
> cc1: some warnings being treated as errors
For the records: including <linux/interrupt.h> fixes this issue.
Thanks for the heads up, will add this in a follow-up post.
Cheers,
Andre
>
>
> vim +878 drivers/firmware/smccc/lfa_fw.c
>
> 863
> 864 static int lfa_register_dt(struct device *dev)
> 865 {
> 866 struct device_node *np;
> 867 unsigned int irq;
> 868
> 869 np = of_find_compatible_node(NULL, NULL, "arm,lfa");
> 870 if (!np)
> 871 return -ENODEV;
> 872
> 873 irq = irq_of_parse_and_map(np, 0);
> 874 of_node_put(np);
> 875 if (!irq)
> 876 return -ENODEV;
> 877
> > 878 return devm_request_threaded_irq(dev, irq, lfa_irq_handler,
> 879 lfa_irq_handler_thread,
> > 880 IRQF_COND_ONESHOT, NULL, NULL);
> 881 }
> 882
>
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2026-03-19 12:53 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 10:33 [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Andre Przywara
2026-03-17 10:33 ` [PATCH v2 1/8] dt-bindings: arm: Add Live Firmware Activation binding Andre Przywara
2026-03-18 8:04 ` Krzysztof Kozlowski
2026-03-18 16:00 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 2/8] firmware: smccc: Add support for Live Firmware Activation (LFA) Andre Przywara
2026-03-18 8:09 ` Krzysztof Kozlowski
2026-03-18 8:12 ` Krzysztof Kozlowski
2026-03-18 15:39 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 3/8] firmware: smccc: lfa: Move image rescanning Andre Przywara
2026-03-17 10:33 ` [PATCH v2 4/8] firmware: smccc: lfa: Add timeout and trigger watchdog Andre Przywara
2026-03-17 10:33 ` [PATCH v2 5/8] firmware: smccc: lfa: Register ACPI notification Andre Przywara
2026-03-17 10:33 ` [PATCH v2 6/8] firmware: smccc: lfa: Add auto_activate sysfs file Andre Przywara
2026-03-18 8:05 ` Krzysztof Kozlowski
2026-03-17 10:33 ` [PATCH v2 7/8] firmware: smccc: lfa: Register DT interrupt Andre Przywara
2026-03-18 8:14 ` Krzysztof Kozlowski
2026-03-18 11:35 ` kernel test robot
2026-03-18 14:21 ` kernel test robot
2026-03-18 14:21 ` kernel test robot
2026-03-19 12:52 ` Andre Przywara
2026-03-17 10:33 ` [PATCH v2 8/8] firmware: smccc: lfa: introduce SMC access lock Andre Przywara
2026-03-18 8:00 ` [PATCH v2 0/8] Arm Live Firmware Activation (LFA) support Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox