From 1ed14652dc324d676f4a93643f3526738ea18214 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:42 +0000 Subject: [PATCH 01/23] firmware: arm_ffa: Replace SCMI by FF-A in the macro Commit 22779149e93d ("firmware: arm_ffa: Emit modalias for FF-A devices") added modalias for FF-A devices. However the macro added used SCMI incorrectly. Replace the reference to SCMI by FF-A and update the macro. (i.e. s/SCMI/FFA/) No functional change. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-1-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index dfda5ffc14db..52b1f09209a0 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -15,7 +15,7 @@ #include "common.h" -#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb" +#define FFA_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb" static DEFINE_IDA(ffa_bus_id); @@ -68,7 +68,7 @@ static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *e { const struct ffa_device *ffa_dev = to_ffa_dev(dev); - return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT, + return add_uevent_var(env, "MODALIAS=" FFA_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, &ffa_dev->uuid); } @@ -77,7 +77,7 @@ static ssize_t modalias_show(struct device *dev, { struct ffa_device *ffa_dev = to_ffa_dev(dev); - return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, + return sysfs_emit(buf, FFA_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, &ffa_dev->uuid); } static DEVICE_ATTR_RO(modalias); From b7c9f32614f17c76ab26b8ee0109c868d7e054fe Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:43 +0000 Subject: [PATCH 02/23] firmware: arm_ffa: Replace UUID buffer to standard UUID format Currently ffa_partition_info structure holds the UUID in the format compatible with the firmware interface. However, most of the functions in the FF-A core driver deals directly with uuid_t type. Replace UUID buffer to standard UUID format in the ffa_partition_info structure. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-2-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/bus.c | 4 +--- include/linux/arm_ffa.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index 52b1f09209a0..a90e2faa9902 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -192,7 +192,6 @@ ffa_device_register(const struct ffa_partition_info *part_info, const struct ffa_ops *ops) { int id, ret; - uuid_t uuid; struct device *dev; struct ffa_device *ffa_dev; @@ -218,8 +217,7 @@ ffa_device_register(const struct ffa_partition_info *part_info, ffa_dev->vm_id = part_info->id; ffa_dev->properties = part_info->properties; ffa_dev->ops = ops; - import_uuid(&uuid, (u8 *)part_info->uuid); - uuid_copy(&ffa_dev->uuid, &uuid); + uuid_copy(&ffa_dev->uuid, &part_info->uuid); ret = device_register(&ffa_dev->dev); if (ret) { diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index 74169dd0f659..abd0208f0f74 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -238,7 +238,7 @@ struct ffa_partition_info { /* partition runs in the AArch64 execution state. */ #define FFA_PARTITION_AARCH64_EXEC BIT(8) u32 properties; - u32 uuid[4]; + uuid_t uuid; }; static inline From 8768972cbbeacd673f09dc1f8e198e03ccfa9f52 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:44 +0000 Subject: [PATCH 03/23] firmware: arm_ffa: Align sync_send_receive{,2} function prototypes Currently ffa_sync_send_receive2() takes UUID as a separate parameter instead of using the one available in ffa_device structure. Change the prototype of ffa_sync_send_receive2() to align with the ffa_sync_send_receive() and use ffa_device->uuid. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-3-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 4 ++-- include/linux/arm_ffa.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 2c2ec3c35f15..037e0d684994 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1018,14 +1018,14 @@ static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz) return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz); } -static int ffa_sync_send_receive2(struct ffa_device *dev, const uuid_t *uuid, +static int ffa_sync_send_receive2(struct ffa_device *dev, struct ffa_send_direct_data2 *data) { if (!drv_info->msg_direct_req2_supp) return -EOPNOTSUPP; return ffa_msg_send_direct_req2(drv_info->vm_id, dev->vm_id, - uuid, data); + &dev->uuid, data); } static int ffa_memory_share(struct ffa_mem_ops_args *args) diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index abd0208f0f74..e8b8ae8b192a 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -439,7 +439,7 @@ struct ffa_msg_ops { int (*sync_send_receive)(struct ffa_device *dev, struct ffa_send_direct_data *data); int (*indirect_send)(struct ffa_device *dev, void *buf, size_t sz); - int (*sync_send_receive2)(struct ffa_device *dev, const uuid_t *uuid, + int (*sync_send_receive2)(struct ffa_device *dev, struct ffa_send_direct_data2 *data); }; From f94ebb72406779637dbdb2c192a5e99f43375036 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:45 +0000 Subject: [PATCH 04/23] firmware: arm_ffa: Fix big-endian support in __ffa_partition_info_get() Currently the FF-A driver doesn't support big-endian correctly. It is hard to regularly test the setup due to lack of test infrastructure and tools. In order to support full stack, we need to take small steps in getting the support for big-endian kernel added slowly. This change fixes the support in __ffa_partition_info_get() so that the response from the firmware are converted correctly as required. With this change, we can enumerate all the FF-A devices correctly in the big-endian kernel. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-4-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 037e0d684994..bc6ffd25ad2e 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -276,9 +276,21 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, } if (buffer && count <= num_partitions) - for (idx = 0; idx < count; idx++) - memcpy(buffer + idx, drv_info->rx_buffer + idx * sz, - buf_sz); + for (idx = 0; idx < count; idx++) { + struct ffa_partition_info_le { + __le16 id; + __le16 exec_ctxt; + __le32 properties; + uuid_t uuid; + } *rx_buf = drv_info->rx_buffer + idx * sz; + struct ffa_partition_info *buf = buffer + idx; + + buf->id = le16_to_cpu(rx_buf->id); + buf->exec_ctxt = le16_to_cpu(rx_buf->exec_ctxt); + buf->properties = le32_to_cpu(rx_buf->properties); + if (buf_sz > 8) + import_uuid(&buf->uuid, (u8 *)&rx_buf->uuid); + } ffa_rx_release(); From 7bc0f589c81d62bc95f9ed142847219fc5d8ef6c Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:46 +0000 Subject: [PATCH 05/23] firmware: arm_ffa: Fix big-endian support in __ffa_partition_info_regs_get() Currently the FF-A driver doesn't support big-endian correctly. It is hard to regularly test the setup due to lack of test infrastructure and tools. In order to support full stack, we need to take small steps in getting the support for big-endian kernel added slowly. This change fixes the support in __ffa_partition_info_regs_get() so that the response from the firmware are converted correctly as required. With this change, we can enumerate all the FF-A devices correctly in the big-endian kernel if the FFA_PARTITION_INFO_REGS_GET is supported. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-5-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index bc6ffd25ad2e..87e106c728b8 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -307,14 +307,24 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, #define CURRENT_INDEX(x) ((u16)(FIELD_GET(CURRENT_INDEX_MASK, (x)))) #define UUID_INFO_TAG(x) ((u16)(FIELD_GET(UUID_INFO_TAG_MASK, (x)))) #define PARTITION_INFO_SZ(x) ((u16)(FIELD_GET(PARTITION_INFO_SZ_MASK, (x)))) +#define PART_INFO_ID_MASK GENMASK(15, 0) +#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16) +#define PART_INFO_PROPS_MASK GENMASK(63, 32) +#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x)))) +#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x)))) +#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x)))) static int __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, struct ffa_partition_info *buffer, int num_parts) { u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0; + struct ffa_partition_info *buf = buffer; ffa_value_t partition_info; do { + __le64 *regs; + int idx; + start_idx = prev_idx ? prev_idx + 1 : 0; invoke_ffa_fn((ffa_value_t){ @@ -338,8 +348,25 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, if (buf_sz > sizeof(*buffer)) buf_sz = sizeof(*buffer); - memcpy(buffer + prev_idx * buf_sz, &partition_info.a3, - (cur_idx - start_idx + 1) * buf_sz); + regs = (void *)&partition_info.a3; + for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) { + union { + uuid_t uuid; + u64 regs[2]; + } uuid_regs = { + .regs = { + le64_to_cpu(*(regs + 1)), + le64_to_cpu(*(regs + 2)), + } + }; + u64 val = *(u64 *)regs; + + buf->id = PART_INFO_ID(val); + buf->exec_ctxt = PART_INFO_EXEC_CXT(val); + buf->properties = PART_INFO_PROPERTIES(val); + uuid_copy(&buf->uuid, &uuid_regs.uuid); + regs += 3; + } prev_idx = cur_idx; } while (cur_idx < (count - 1)); From 3c3d6767466ea316869c9f2bdd976aec8ce44545 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 17 Feb 2025 15:38:47 +0000 Subject: [PATCH 06/23] firmware: arm_ffa: Refactor addition of partition information into XArray Move the common code handling addition of the FF-A partition information into the XArray as a new routine. No functional change. Signed-off-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-6-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 47 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 87e106c728b8..2994b5ee63bc 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1423,11 +1423,30 @@ static struct notifier_block ffa_bus_nb = { .notifier_call = ffa_bus_notifier, }; +static int ffa_xa_add_partition_info(int vm_id) +{ + struct ffa_dev_part_info *info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + rwlock_init(&info->rw_lock); + ret = xa_insert(&drv_info->partition_info, vm_id, info, GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save partition ID 0x%x - ret:%d. Abort.\n", + __func__, vm_id, ret); + kfree(info); + } + + return ret; +} + static int ffa_setup_partitions(void) { int count, idx, ret; struct ffa_device *ffa_dev; - struct ffa_dev_part_info *info; struct ffa_partition_info *pbuf, *tpbuf; if (drv_info->version == FFA_VERSION_1_0) { @@ -1461,39 +1480,17 @@ static int ffa_setup_partitions(void) !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) ffa_mode_32bit_set(ffa_dev); - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (ffa_xa_add_partition_info(ffa_dev->vm_id)) { ffa_device_unregister(ffa_dev); continue; } - rwlock_init(&info->rw_lock); - ret = xa_insert(&drv_info->partition_info, tpbuf->id, - info, GFP_KERNEL); - if (ret) { - pr_err("%s: failed to save partition ID 0x%x - ret:%d\n", - __func__, tpbuf->id, ret); - ffa_device_unregister(ffa_dev); - kfree(info); - } } kfree(pbuf); /* Allocate for the host */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - /* Already registered devices are freed on bus_exit */ - ffa_partitions_cleanup(); - return -ENOMEM; - } - - rwlock_init(&info->rw_lock); - ret = xa_insert(&drv_info->partition_info, drv_info->vm_id, - info, GFP_KERNEL); + ret = ffa_xa_add_partition_info(drv_info->vm_id); if (ret) { - pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n", - __func__, drv_info->vm_id, ret); - kfree(info); /* Already registered devices are freed on bus_exit */ ffa_partitions_cleanup(); } From 2f622a8b0722d332a2a149794a3add47bc9bdcf3 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:48 +0000 Subject: [PATCH 07/23] firmware: arm_ffa: Handle the presence of host partition in the partition info Currently it is assumed that the firmware doesn't present the host partition in the list of partitions presented as part of the response to PARTITION_INFO_GET from the firmware. However, there are few platforms that prefer to present the same in the list of partitions. It is not manadatory but not restricted as well. So handle the same by making sure to check the presence of the host VM ID in the XArray partition information maintained/managed in the driver before attempting to add it. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-7-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 2994b5ee63bc..320ae654cb96 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1488,6 +1488,10 @@ static int ffa_setup_partitions(void) kfree(pbuf); + /* Check if the host is already added as part of partition info */ + if (xa_load(&drv_info->partition_info, drv_info->vm_id)) + return 0; + /* Allocate for the host */ ret = ffa_xa_add_partition_info(drv_info->vm_id); if (ret) { From 46dcd68aaccac0812c12ec3f4e59c8963e2760ad Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:49 +0000 Subject: [PATCH 08/23] firmware: arm_ffa: Unregister the FF-A devices when cleaning up the partitions Both the FF-A core and the bus were in a single module before the commit 18c250bd7ed0 ("firmware: arm_ffa: Split bus and driver into distinct modules"). The arm_ffa_bus_exit() takes care of unregistering all the FF-A devices. Now that there are 2 distinct modules, if the core driver is unloaded and reloaded, it will end up adding duplicate FF-A devices as the previously registered devices weren't unregistered when we cleaned up the modules. Fix the same by unregistering all the FF-A devices on the FF-A bus during the cleaning up of the partitions and hence the cleanup of the module. Fixes: 18c250bd7ed0 ("firmware: arm_ffa: Split bus and driver into distinct modules") Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-8-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/bus.c | 3 ++- drivers/firmware/arm_ffa/driver.c | 7 ++++--- include/linux/arm_ffa.h | 3 +++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index a90e2faa9902..98118823cf84 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -160,11 +160,12 @@ static int __ffa_devices_unregister(struct device *dev, void *data) return 0; } -static void ffa_devices_unregister(void) +void ffa_devices_unregister(void) { bus_for_each_dev(&ffa_bus_type, NULL, NULL, __ffa_devices_unregister); } +EXPORT_SYMBOL_GPL(ffa_devices_unregister); bool ffa_device_is_valid(struct ffa_device *ffa_dev) { diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 320ae654cb96..15305920ca9f 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1494,10 +1494,8 @@ static int ffa_setup_partitions(void) /* Allocate for the host */ ret = ffa_xa_add_partition_info(drv_info->vm_id); - if (ret) { - /* Already registered devices are freed on bus_exit */ + if (ret) ffa_partitions_cleanup(); - } return ret; } @@ -1507,6 +1505,9 @@ static void ffa_partitions_cleanup(void) struct ffa_dev_part_info *info; unsigned long idx; + /* Clean up/free all registered devices */ + ffa_devices_unregister(); + xa_for_each(&drv_info->partition_info, idx, info) { xa_erase(&drv_info->partition_info, idx); kfree(info); diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index e8b8ae8b192a..ca2ad5b0ac43 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -176,6 +176,7 @@ void ffa_device_unregister(struct ffa_device *ffa_dev); int ffa_driver_register(struct ffa_driver *driver, struct module *owner, const char *mod_name); void ffa_driver_unregister(struct ffa_driver *driver); +void ffa_devices_unregister(void); bool ffa_device_is_valid(struct ffa_device *ffa_dev); #else @@ -188,6 +189,8 @@ ffa_device_register(const struct ffa_partition_info *part_info, static inline void ffa_device_unregister(struct ffa_device *dev) {} +static inline void ffa_devices_unregister(void) {} + static inline int ffa_driver_register(struct ffa_driver *driver, struct module *owner, const char *mod_name) From 84968e32d301f80bd37fa8d4f370528b714bdc2f Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:50 +0000 Subject: [PATCH 09/23] firmware: arm_ffa: Helper to check if a partition can receive REQUEST2 messages Add a helper that allows FF-A drivers to check if the partition can receive the direct requests via the FFA_MSG_SEND_DIRECT_REQ2 ABI. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-9-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- include/linux/arm_ffa.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index ca2ad5b0ac43..761ea8fe3bb6 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -240,6 +240,10 @@ struct ffa_partition_info { #define FFA_PARTITION_NOTIFICATION_RECV BIT(3) /* partition runs in the AArch64 execution state. */ #define FFA_PARTITION_AARCH64_EXEC BIT(8) +/* partition supports receipt of direct request2 */ +#define FFA_PARTITION_DIRECT_REQ2_RECV BIT(9) +/* partition can send direct request2. */ +#define FFA_PARTITION_DIRECT_REQ2_SEND BIT(10) u32 properties; uuid_t uuid; }; @@ -259,6 +263,10 @@ bool ffa_partition_check_property(struct ffa_device *dev, u32 property) #define ffa_partition_supports_direct_recv(dev) \ ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_RECV) +#define ffa_partition_supports_direct_req2_recv(dev) \ + (ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_REQ2_RECV) && \ + !dev->mode_32bit) + /* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */ struct ffa_send_direct_data { unsigned long data0; /* w3/x3 */ From 910cc1acc9b42186db586c2fa9b48de34d651e7b Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:51 +0000 Subject: [PATCH 10/23] firmware: arm_ffa: Add support for passing UUID in FFA_MSG_SEND2 FF-A v1.2 introduces UUID field in partition message header used in FFA_MSG_SEND2 to enable partitions/endpoints exposing multiple UUIDs. Add the support for passing UUID in FFA_MSG_SEND2. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-10-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 7 ++++--- include/linux/arm_ffa.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 15305920ca9f..545b1772df00 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -484,9 +484,9 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, return -EINVAL; } -static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz) +static int ffa_msg_send2(struct ffa_device *dev, u16 src_id, void *buf, size_t sz) { - u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); + u32 src_dst_ids = PACK_TARGET_INFO(src_id, dev->vm_id); struct ffa_indirect_msg_hdr *msg; ffa_value_t ret; int retval = 0; @@ -502,6 +502,7 @@ static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz) msg->offset = sizeof(*msg); msg->send_recv_id = src_dst_ids; msg->size = sz; + uuid_copy(&msg->uuid, &dev->uuid); memcpy((u8 *)msg + msg->offset, buf, sz); /* flags = 0, sender VMID = 0 works for both physical/virtual NS */ @@ -1054,7 +1055,7 @@ static int ffa_sync_send_receive(struct ffa_device *dev, static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz) { - return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz); + return ffa_msg_send2(dev, drv_info->vm_id, buf, sz); } static int ffa_sync_send_receive2(struct ffa_device *dev, diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index 761ea8fe3bb6..bd78deeff284 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -282,6 +282,7 @@ struct ffa_indirect_msg_hdr { u32 offset; u32 send_recv_id; u32 size; + uuid_t uuid; }; /* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP}2 which pass data via registers */ From 9fac08d9d9855fbb49bf2342c964ad3d861bfafe Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:52 +0000 Subject: [PATCH 11/23] firmware: arm_ffa: Upgrade FF-A version to v1.2 in the driver The basic and mandatory features of FF-A v1.2 are all supported now. The driver supported version can be bumped from v1.1 to v1.2 Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-11-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 +- include/linux/arm_ffa.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 545b1772df00..d8421a32a92f 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -44,7 +44,7 @@ #include "common.h" -#define FFA_DRIVER_VERSION FFA_VERSION_1_1 +#define FFA_DRIVER_VERSION FFA_VERSION_1_2 #define FFA_MIN_VERSION FFA_VERSION_1_0 #define SENDER_ID_MASK GENMASK(31, 16) diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index bd78deeff284..4fcbdc70cbc9 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -112,6 +112,7 @@ FIELD_PREP(FFA_MINOR_VERSION_MASK, (minor))) #define FFA_VERSION_1_0 FFA_PACK_VERSION_INFO(1, 0) #define FFA_VERSION_1_1 FFA_PACK_VERSION_INFO(1, 1) +#define FFA_VERSION_1_2 FFA_PACK_VERSION_INFO(1, 2) /** * FF-A specification mentions explicitly about '4K pages'. This should From efff6a7f16b34fd902f342b58bd8bafc2d6f2fd1 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:53 +0000 Subject: [PATCH 12/23] firmware: arm_ffa: Reject higher major version as incompatible When the firmware compatibility was handled previously in the commit 8e3f9da608f1 ("firmware: arm_ffa: Handle compatibility with different firmware versions"), we only addressed firmware versions that have higher minor versions compared to the driver version which is should be considered compatible unless the firmware returns NOT_SUPPORTED. However, if the firmware reports higher major version than the driver supported, we need to reject it. If the firmware can work in a compatible mode with the driver requested version, it must return the same major version as requested. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-12-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index d8421a32a92f..ad2f6b410e44 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -150,6 +150,14 @@ static int ffa_version_check(u32 *version) return -EOPNOTSUPP; } + if (FFA_MAJOR_VERSION(ver.a0) > FFA_MAJOR_VERSION(FFA_DRIVER_VERSION)) { + pr_err("Incompatible v%d.%d! Latest supported v%d.%d\n", + FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), + FFA_MAJOR_VERSION(FFA_DRIVER_VERSION), + FFA_MINOR_VERSION(FFA_DRIVER_VERSION)); + return -EINVAL; + } + if (ver.a0 < FFA_MIN_VERSION) { pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n", FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0), From 9982cabf403fbd06a120a2d5b21830effd32b370 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:54 +0000 Subject: [PATCH 13/23] firmware: arm_ffa: Remove unnecessary declaration of ffa_partitions_cleanup() In order to keep the uniformity, just move the ffa_partitions_cleanup() before it's first usage and drop the unnecessary forward declaration. No functional change. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-13-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 33 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index ad2f6b410e44..43e033edd6c7 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -114,7 +114,6 @@ struct ffa_drv_info { }; static struct ffa_drv_info *drv_info; -static void ffa_partitions_cleanup(void); /* * The driver must be able to support all the versions from the earliest @@ -1452,6 +1451,22 @@ static int ffa_xa_add_partition_info(int vm_id) return ret; } +static void ffa_partitions_cleanup(void) +{ + struct ffa_dev_part_info *info; + unsigned long idx; + + /* Clean up/free all registered devices */ + ffa_devices_unregister(); + + xa_for_each(&drv_info->partition_info, idx, info) { + xa_erase(&drv_info->partition_info, idx); + kfree(info); + } + + xa_destroy(&drv_info->partition_info); +} + static int ffa_setup_partitions(void) { int count, idx, ret; @@ -1509,22 +1524,6 @@ static int ffa_setup_partitions(void) return ret; } -static void ffa_partitions_cleanup(void) -{ - struct ffa_dev_part_info *info; - unsigned long idx; - - /* Clean up/free all registered devices */ - ffa_devices_unregister(); - - xa_for_each(&drv_info->partition_info, idx, info) { - xa_erase(&drv_info->partition_info, idx); - kfree(info); - } - - xa_destroy(&drv_info->partition_info); -} - /* FFA FEATURE IDs */ #define FFA_FEAT_NOTIFICATION_PENDING_INT (1) #define FFA_FEAT_SCHEDULE_RECEIVER_INT (2) From 07b760e713255a2224cfaad62eeaae85de913bac Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:55 +0000 Subject: [PATCH 14/23] firmware: arm_ffa: Refactoring to prepare for framework notification support Currently, the framework notifications are not supported at all. handle_notif_callbacks() doesn't handle them though it is called with framework bitmap. Make that explicit by adding checks for the same. Also, we need to further classify the framework notifications as Secure Partition Manager(SPM) and NonSecure Hypervisor(NS_HYP). Extend/change notify_type enumeration to accommodate all the 4 type and rejig the values so that it can be reused in the bitmap enable mask macros. While at this, move ffa_notify_type_get() so that it can be used in notifier_hash_node_get() in the future. No functional change. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-14-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 57 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 43e033edd6c7..0abbf08bc8d3 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -807,6 +807,13 @@ static int ffa_notification_bitmap_destroy(void) return 0; } +enum notify_type { + SECURE_PARTITION, + NON_SECURE_VM, + SPM_FRAMEWORK, + NS_HYP_FRAMEWORK, +}; + #define NOTIFICATION_LOW_MASK GENMASK(31, 0) #define NOTIFICATION_HIGH_MASK GENMASK(63, 32) #define NOTIFICATION_BITMAP_HIGH(x) \ @@ -830,10 +837,17 @@ static int ffa_notification_bitmap_destroy(void) #define MAX_IDS_32 10 #define PER_VCPU_NOTIFICATION_FLAG BIT(0) -#define SECURE_PARTITION_BITMAP BIT(0) -#define NON_SECURE_VM_BITMAP BIT(1) -#define SPM_FRAMEWORK_BITMAP BIT(2) -#define NS_HYP_FRAMEWORK_BITMAP BIT(3) +#define SECURE_PARTITION_BITMAP_ENABLE BIT(SECURE_PARTITION) +#define NON_SECURE_VM_BITMAP_ENABLE BIT(NON_SECURE_VM) +#define SPM_FRAMEWORK_BITMAP_ENABLE BIT(SPM_FRAMEWORK) +#define NS_HYP_FRAMEWORK_BITMAP_ENABLE BIT(NS_HYP_FRAMEWORK) +#define FFA_BITMAP_ENABLE_MASK \ + (SECURE_PARTITION_BITMAP_ENABLE | SPM_FRAMEWORK_BITMAP_ENABLE) + +#define FFA_SECURE_PARTITION_ID_FLAG BIT(15) + +#define SPM_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_LOW(x) +#define NS_HYP_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_HIGH(x) static int ffa_notification_bind_common(u16 dst_id, u64 bitmap, u32 flags, bool is_bind) @@ -1098,16 +1112,8 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args) return ffa_memory_ops(FFA_MEM_LEND, args); } -#define FFA_SECURE_PARTITION_ID_FLAG BIT(15) - #define ffa_notifications_disabled() (!drv_info->notif_enabled) -enum notify_type { - NON_SECURE_VM, - SECURE_PARTITION, - FRAMEWORK, -}; - struct notifier_cb_info { struct hlist_node hnode; ffa_notifier_cb cb; @@ -1166,6 +1172,14 @@ static int ffa_notification_unbind(u16 dst_id, u64 bitmap) return ffa_notification_bind_common(dst_id, bitmap, 0, false); } +static enum notify_type ffa_notify_type_get(u16 vm_id) +{ + if (vm_id & FFA_SECURE_PARTITION_ID_FLAG) + return SECURE_PARTITION; + else + return NON_SECURE_VM; +} + /* Should be called while the notify_lock is taken */ static struct notifier_cb_info * notifier_hash_node_get(u16 notify_id, enum notify_type type) @@ -1209,14 +1223,6 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb, return 0; } -static enum notify_type ffa_notify_type_get(u16 vm_id) -{ - if (vm_id & FFA_SECURE_PARTITION_ID_FLAG) - return SECURE_PARTITION; - else - return NON_SECURE_VM; -} - static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) { int rc; @@ -1299,6 +1305,9 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type) int notify_id; struct notifier_cb_info *cb_info = NULL; + if (type == SPM_FRAMEWORK || type == NS_HYP_FRAMEWORK) + return; + for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap; notify_id++, bitmap >>= 1) { if (!(bitmap & 1)) @@ -1318,16 +1327,18 @@ static void notif_get_and_handle(void *unused) int rc; struct ffa_notify_bitmaps bitmaps; - rc = ffa_notification_get(SECURE_PARTITION_BITMAP | - SPM_FRAMEWORK_BITMAP, &bitmaps); + rc = ffa_notification_get(FFA_BITMAP_ENABLE_MASK, &bitmaps); if (rc) { pr_err("Failed to retrieve notifications with %d!\n", rc); return; } + handle_notif_callbacks(SPM_FRAMEWORK_BITMAP(bitmaps.arch_map), + SPM_FRAMEWORK); + handle_notif_callbacks(NS_HYP_FRAMEWORK_BITMAP(bitmaps.arch_map), + NS_HYP_FRAMEWORK); handle_notif_callbacks(bitmaps.vm_map, NON_SECURE_VM); handle_notif_callbacks(bitmaps.sp_map, SECURE_PARTITION); - handle_notif_callbacks(bitmaps.arch_map, FRAMEWORK); } static void From a3d73fe8ae5db389f2108a052c0a9c3c3fbc29cf Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:56 +0000 Subject: [PATCH 15/23] firmware: arm_ffa: Stash ffa_device instead of notify_type in notifier_cb_info Currently, we store the type of the notification in the notifier_cb_info structure that is put into the hast list to identify if the notification block is for the secure partition or the non secure VM. In order to support framework notifications to reuse the hash list and to avoid creating one for each time, we need store the ffa_device pointer itself as the same notification ID in framework notifications can be registered by multiple FF-A devices. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-15-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 0abbf08bc8d3..5863272f45d9 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1116,9 +1116,9 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args) struct notifier_cb_info { struct hlist_node hnode; + struct ffa_device *dev; ffa_notifier_cb cb; void *cb_data; - enum notify_type type; }; static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, @@ -1187,17 +1187,18 @@ notifier_hash_node_get(u16 notify_id, enum notify_type type) struct notifier_cb_info *node; hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id) - if (type == node->type) + if (type == ffa_notify_type_get(node->dev->vm_id)) return node; return NULL; } static int -update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb, +update_notifier_cb(struct ffa_device *dev, int notify_id, ffa_notifier_cb cb, void *cb_data, bool is_registration) { struct notifier_cb_info *cb_info = NULL; + enum notify_type type = ffa_notify_type_get(dev->vm_id); bool cb_found; cb_info = notifier_hash_node_get(notify_id, type); @@ -1211,7 +1212,7 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb, if (!cb_info) return -ENOMEM; - cb_info->type = type; + cb_info->dev = dev; cb_info->cb = cb; cb_info->cb_data = cb_data; @@ -1226,7 +1227,6 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb, static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) { int rc; - enum notify_type type = ffa_notify_type_get(dev->vm_id); if (ffa_notifications_disabled()) return -EOPNOTSUPP; @@ -1236,7 +1236,7 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) mutex_lock(&drv_info->notify_lock); - rc = update_notifier_cb(notify_id, type, NULL, NULL, false); + rc = update_notifier_cb(dev, notify_id, NULL, NULL, false); if (rc) { pr_err("Could not unregister notification callback\n"); mutex_unlock(&drv_info->notify_lock); @@ -1255,7 +1255,6 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, { int rc; u32 flags = 0; - enum notify_type type = ffa_notify_type_get(dev->vm_id); if (ffa_notifications_disabled()) return -EOPNOTSUPP; @@ -1274,7 +1273,7 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, return rc; } - rc = update_notifier_cb(notify_id, type, cb, cb_data, true); + rc = update_notifier_cb(dev, notify_id, cb, cb_data, true); if (rc) { pr_err("Failed to register callback for %d - %d\n", notify_id, rc); From c10debfe7f028c11f7a501a0f8e937c9be9e5327 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:57 +0000 Subject: [PATCH 16/23] firmware: arm_ffa: Add support for {un,}registration of framework notifications Framework notifications are doorbells that are rung by the partition managers to signal common events to an endpoint. These doorbells cannot be rung by an endpoint directly. A partition manager can signal a Framework notification in response to an FF-A ABI invocation by an endpoint. Two additional notify_ops interface is being added for any FF-A device/ driver to register and unregister for such a framework notifications. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-16-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 113 ++++++++++++++++++++++++------ include/linux/arm_ffa.h | 5 ++ 2 files changed, 97 insertions(+), 21 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 5863272f45d9..a889ad6d94ac 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1117,6 +1117,7 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args) struct notifier_cb_info { struct hlist_node hnode; struct ffa_device *dev; + ffa_fwk_notifier_cb fwk_cb; ffa_notifier_cb cb; void *cb_data; }; @@ -1180,28 +1181,61 @@ static enum notify_type ffa_notify_type_get(u16 vm_id) return NON_SECURE_VM; } -/* Should be called while the notify_lock is taken */ +/* notifier_hnode_get* should be called with notify_lock held */ static struct notifier_cb_info * -notifier_hash_node_get(u16 notify_id, enum notify_type type) +notifier_hnode_get_by_vmid(u16 notify_id, int vmid) { struct notifier_cb_info *node; hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id) - if (type == ffa_notify_type_get(node->dev->vm_id)) + if (node->fwk_cb && vmid == node->dev->vm_id) + return node; + + return NULL; +} + +static struct notifier_cb_info * +notifier_hnode_get_by_vmid_uuid(u16 notify_id, int vmid, const uuid_t *uuid) +{ + struct notifier_cb_info *node; + + if (uuid_is_null(uuid)) + return notifier_hnode_get_by_vmid(notify_id, vmid); + + hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id) + if (node->fwk_cb && vmid == node->dev->vm_id && + uuid_equal(&node->dev->uuid, uuid)) + return node; + + return NULL; +} + +static struct notifier_cb_info * +notifier_hnode_get_by_type(u16 notify_id, enum notify_type type) +{ + struct notifier_cb_info *node; + + hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id) + if (node->cb && type == ffa_notify_type_get(node->dev->vm_id)) return node; return NULL; } static int -update_notifier_cb(struct ffa_device *dev, int notify_id, ffa_notifier_cb cb, - void *cb_data, bool is_registration) +update_notifier_cb(struct ffa_device *dev, int notify_id, void *cb, + void *cb_data, bool is_registration, bool is_framework) { struct notifier_cb_info *cb_info = NULL; enum notify_type type = ffa_notify_type_get(dev->vm_id); bool cb_found; - cb_info = notifier_hash_node_get(notify_id, type); + if (is_framework) + cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, dev->vm_id, + &dev->uuid); + else + cb_info = notifier_hnode_get_by_type(notify_id, type); + cb_found = !!cb_info; if (!(is_registration ^ cb_found)) @@ -1213,8 +1247,11 @@ update_notifier_cb(struct ffa_device *dev, int notify_id, ffa_notifier_cb cb, return -ENOMEM; cb_info->dev = dev; - cb_info->cb = cb; cb_info->cb_data = cb_data; + if (is_framework) + cb_info->fwk_cb = cb; + else + cb_info->cb = cb; hash_add(drv_info->notifier_hash, &cb_info->hnode, notify_id); } else { @@ -1224,7 +1261,8 @@ update_notifier_cb(struct ffa_device *dev, int notify_id, ffa_notifier_cb cb, return 0; } -static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) +static int __ffa_notify_relinquish(struct ffa_device *dev, int notify_id, + bool is_framework) { int rc; @@ -1236,22 +1274,35 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) mutex_lock(&drv_info->notify_lock); - rc = update_notifier_cb(dev, notify_id, NULL, NULL, false); + rc = update_notifier_cb(dev, notify_id, NULL, NULL, false, + is_framework); if (rc) { pr_err("Could not unregister notification callback\n"); mutex_unlock(&drv_info->notify_lock); return rc; } - rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id)); + if (!is_framework) + rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id)); mutex_unlock(&drv_info->notify_lock); return rc; } -static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, - ffa_notifier_cb cb, void *cb_data, int notify_id) +static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) +{ + return __ffa_notify_relinquish(dev, notify_id, false); +} + +static int ffa_fwk_notify_relinquish(struct ffa_device *dev, int notify_id) +{ + return __ffa_notify_relinquish(dev, notify_id, true); +} + +static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, + void *cb, void *cb_data, + int notify_id, bool is_framework) { int rc; u32 flags = 0; @@ -1264,26 +1315,44 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, mutex_lock(&drv_info->notify_lock); - if (is_per_vcpu) - flags = PER_VCPU_NOTIFICATION_FLAG; + if (!is_framework) { + if (is_per_vcpu) + flags = PER_VCPU_NOTIFICATION_FLAG; - rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags); - if (rc) { - mutex_unlock(&drv_info->notify_lock); - return rc; + rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags); + if (rc) { + mutex_unlock(&drv_info->notify_lock); + return rc; + } } - rc = update_notifier_cb(dev, notify_id, cb, cb_data, true); + rc = update_notifier_cb(dev, notify_id, cb, cb_data, true, + is_framework); if (rc) { pr_err("Failed to register callback for %d - %d\n", notify_id, rc); - ffa_notification_unbind(dev->vm_id, BIT(notify_id)); + if (!is_framework) + ffa_notification_unbind(dev->vm_id, BIT(notify_id)); } mutex_unlock(&drv_info->notify_lock); return rc; } +static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, + ffa_notifier_cb cb, void *cb_data, int notify_id) +{ + return __ffa_notify_request(dev, is_per_vcpu, cb, cb_data, notify_id, + false); +} + +static int +ffa_fwk_notify_request(struct ffa_device *dev, ffa_fwk_notifier_cb cb, + void *cb_data, int notify_id) +{ + return __ffa_notify_request(dev, false, cb, cb_data, notify_id, true); +} + static int ffa_notify_send(struct ffa_device *dev, int notify_id, bool is_per_vcpu, u16 vcpu) { @@ -1313,7 +1382,7 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type) continue; mutex_lock(&drv_info->notify_lock); - cb_info = notifier_hash_node_get(notify_id, type); + cb_info = notifier_hnode_get_by_type(notify_id, type); mutex_unlock(&drv_info->notify_lock); if (cb_info && cb_info->cb) @@ -1386,6 +1455,8 @@ static const struct ffa_notifier_ops ffa_drv_notifier_ops = { .sched_recv_cb_unregister = ffa_sched_recv_cb_unregister, .notify_request = ffa_notify_request, .notify_relinquish = ffa_notify_relinquish, + .fwk_notify_request = ffa_fwk_notify_request, + .fwk_notify_relinquish = ffa_fwk_notify_relinquish, .notify_send = ffa_notify_send, }; diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index 4fcbdc70cbc9..5bded24dc24f 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -468,6 +468,7 @@ struct ffa_cpu_ops { typedef void (*ffa_sched_recv_cb)(u16 vcpu, bool is_per_vcpu, void *cb_data); typedef void (*ffa_notifier_cb)(int notify_id, void *cb_data); +typedef void (*ffa_fwk_notifier_cb)(int notify_id, void *cb_data, void *buf); struct ffa_notifier_ops { int (*sched_recv_cb_register)(struct ffa_device *dev, @@ -476,6 +477,10 @@ struct ffa_notifier_ops { int (*notify_request)(struct ffa_device *dev, bool per_vcpu, ffa_notifier_cb cb, void *cb_data, int notify_id); int (*notify_relinquish)(struct ffa_device *dev, int notify_id); + int (*fwk_notify_request)(struct ffa_device *dev, + ffa_fwk_notifier_cb cb, void *cb_data, + int notify_id); + int (*fwk_notify_relinquish)(struct ffa_device *dev, int notify_id); int (*notify_send)(struct ffa_device *dev, int notify_id, bool per_vcpu, u16 vcpu); }; From 285a5ea0f542db94c3ed11e01a71abb47d15cbf5 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:58 +0000 Subject: [PATCH 17/23] firmware: arm_ffa: Add support for handling framework notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently FF-A specification defines only one framework notification: RX buffer full notification. This notification is signaled by the partition manager during transmission of a partition message through indirect messaging to, 1. Notify an endpoint that it has a pending message in its Rx buffer. 2. Inform the message receiver’s scheduler via the schedule receiver interrupt that the receiver must be run. In response to an FFA_MSG_SEND2 invocation by a sender endpoint, the framework performs the following actions after the message is copied from the Tx buffer of the sender to the Rx buffer of the receiver: 1. The notification is pended in the framework notification bitmap of the receiver. 2. The partition manager of the endpoint that contains receiver’s scheduler pends the schedule receiver interrupt for this endpoint. The receiver receives the notification and copies out the message from its Rx buffer. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-17-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 50 ++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index a889ad6d94ac..5441c4d88780 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -848,6 +848,7 @@ enum notify_type { #define SPM_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_LOW(x) #define NS_HYP_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_HIGH(x) +#define FRAMEWORK_NOTIFY_RX_BUFFER_FULL BIT(0) static int ffa_notification_bind_common(u16 dst_id, u64 bitmap, u32 flags, bool is_bind) @@ -1373,9 +1374,6 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type) int notify_id; struct notifier_cb_info *cb_info = NULL; - if (type == SPM_FRAMEWORK || type == NS_HYP_FRAMEWORK) - return; - for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap; notify_id++, bitmap >>= 1) { if (!(bitmap & 1)) @@ -1390,6 +1388,46 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type) } } +static void handle_fwk_notif_callbacks(u32 bitmap) +{ + void *buf; + uuid_t uuid; + int notify_id = 0, target; + struct ffa_indirect_msg_hdr *msg; + struct notifier_cb_info *cb_info = NULL; + + /* Only one framework notification defined and supported for now */ + if (!(bitmap & FRAMEWORK_NOTIFY_RX_BUFFER_FULL)) + return; + + mutex_lock(&drv_info->rx_lock); + + msg = drv_info->rx_buffer; + buf = kmemdup((void *)msg + msg->offset, msg->size, GFP_KERNEL); + if (!buf) { + mutex_unlock(&drv_info->rx_lock); + return; + } + + target = SENDER_ID(msg->send_recv_id); + if (msg->offset >= sizeof(*msg)) + uuid_copy(&uuid, &msg->uuid); + else + uuid_copy(&uuid, &uuid_null); + + mutex_unlock(&drv_info->rx_lock); + + ffa_rx_release(); + + mutex_lock(&drv_info->notify_lock); + cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid); + mutex_unlock(&drv_info->notify_lock); + + if (cb_info && cb_info->fwk_cb) + cb_info->fwk_cb(notify_id, cb_info->cb_data, buf); + kfree(buf); +} + static void notif_get_and_handle(void *unused) { int rc; @@ -1401,10 +1439,8 @@ static void notif_get_and_handle(void *unused) return; } - handle_notif_callbacks(SPM_FRAMEWORK_BITMAP(bitmaps.arch_map), - SPM_FRAMEWORK); - handle_notif_callbacks(NS_HYP_FRAMEWORK_BITMAP(bitmaps.arch_map), - NS_HYP_FRAMEWORK); + handle_fwk_notif_callbacks(SPM_FRAMEWORK_BITMAP(bitmaps.arch_map)); + handle_fwk_notif_callbacks(NS_HYP_FRAMEWORK_BITMAP(bitmaps.arch_map)); handle_notif_callbacks(bitmaps.vm_map, NON_SECURE_VM); handle_notif_callbacks(bitmaps.sp_map, SECURE_PARTITION); } From be61da938576671c664382a059f961d7b4b2fc41 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:38:59 +0000 Subject: [PATCH 18/23] firmware: arm_ffa: Allow multiple UUIDs per partition to register SRI callback A partition can implement multiple UUIDs and currently we successfully register each UUID service as a FF-A device. However when adding the same partition info to the XArray which tracks the SRI callbacks more than once, it fails. In order to allow multiple UUIDs per partition to register SRI callbacks the partition information stored in the XArray needs to be extended to a listed list. A function to remove the list of partition information in the XArray is not added as there are no users at the time. All the partitions are added at probe/initialisation and removed at cleanup stage. Tested-by: Viresh Kumar Message-Id: <20250217-ffa_updates-v3-18-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 159 ++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 42 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 5441c4d88780..db6334f0c532 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -925,27 +925,32 @@ struct ffa_dev_part_info { ffa_sched_recv_cb callback; void *cb_data; rwlock_t rw_lock; + struct ffa_device *dev; + struct list_head node; }; static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) { - struct ffa_dev_part_info *partition; + struct ffa_dev_part_info *partition = NULL, *tmp; ffa_sched_recv_cb callback; + struct list_head *phead; void *cb_data; - partition = xa_load(&drv_info->partition_info, part_id); - if (!partition) { + phead = xa_load(&drv_info->partition_info, part_id); + if (!phead) { pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); return; } - read_lock(&partition->rw_lock); - callback = partition->callback; - cb_data = partition->cb_data; - read_unlock(&partition->rw_lock); + list_for_each_entry_safe(partition, tmp, phead, node) { + read_lock(&partition->rw_lock); + callback = partition->callback; + cb_data = partition->cb_data; + read_unlock(&partition->rw_lock); - if (callback) - callback(vcpu, is_per_vcpu, cb_data); + if (callback) + callback(vcpu, is_per_vcpu, cb_data); + } } static void ffa_notification_info_get(void) @@ -1123,18 +1128,29 @@ struct notifier_cb_info { void *cb_data; }; -static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, - void *cb_data, bool is_registration) +static int +ffa_sched_recv_cb_update(struct ffa_device *dev, ffa_sched_recv_cb callback, + void *cb_data, bool is_registration) { - struct ffa_dev_part_info *partition; + struct ffa_dev_part_info *partition = NULL, *tmp; + struct list_head *phead; bool cb_valid; if (ffa_notifications_disabled()) return -EOPNOTSUPP; - partition = xa_load(&drv_info->partition_info, part_id); + phead = xa_load(&drv_info->partition_info, dev->vm_id); + if (!phead) { + pr_err("%s: Invalid partition ID 0x%x\n", __func__, dev->vm_id); + return -EINVAL; + } + + list_for_each_entry_safe(partition, tmp, phead, node) + if (partition->dev == dev) + break; + if (!partition) { - pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); + pr_err("%s: No such partition ID 0x%x\n", __func__, dev->vm_id); return -EINVAL; } @@ -1156,12 +1172,12 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, static int ffa_sched_recv_cb_register(struct ffa_device *dev, ffa_sched_recv_cb cb, void *cb_data) { - return ffa_sched_recv_cb_update(dev->vm_id, cb, cb_data, true); + return ffa_sched_recv_cb_update(dev, cb, cb_data, true); } static int ffa_sched_recv_cb_unregister(struct ffa_device *dev) { - return ffa_sched_recv_cb_update(dev->vm_id, NULL, NULL, false); + return ffa_sched_recv_cb_update(dev, NULL, NULL, false); } static int ffa_notification_bind(u16 dst_id, u64 bitmap, u32 flags) @@ -1548,37 +1564,101 @@ static struct notifier_block ffa_bus_nb = { .notifier_call = ffa_bus_notifier, }; -static int ffa_xa_add_partition_info(int vm_id) +static int ffa_xa_add_partition_info(struct ffa_device *dev) { struct ffa_dev_part_info *info; - int ret; + struct list_head *head, *phead; + int ret = -ENOMEM; + + phead = xa_load(&drv_info->partition_info, dev->vm_id); + if (phead) { + head = phead; + list_for_each_entry(info, head, node) { + if (info->dev == dev) { + pr_err("%s: duplicate dev %p part ID 0x%x\n", + __func__, dev, dev->vm_id); + return -EEXIST; + } + } + } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) - return -ENOMEM; + return ret; rwlock_init(&info->rw_lock); - ret = xa_insert(&drv_info->partition_info, vm_id, info, GFP_KERNEL); - if (ret) { - pr_err("%s: failed to save partition ID 0x%x - ret:%d. Abort.\n", - __func__, vm_id, ret); - kfree(info); + info->dev = dev; + + if (!phead) { + phead = kzalloc(sizeof(*phead), GFP_KERNEL); + if (!phead) + goto free_out; + + INIT_LIST_HEAD(phead); + + ret = xa_insert(&drv_info->partition_info, dev->vm_id, phead, + GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save part ID 0x%x Ret:%d\n", + __func__, dev->vm_id, ret); + goto free_out; + } } + list_add(&info->node, phead); + return 0; + +free_out: + kfree(phead); + kfree(info); + return ret; +} + +static int ffa_setup_host_partition(int vm_id) +{ + struct ffa_partition_info buf = { 0 }; + struct ffa_device *ffa_dev; + int ret; + + buf.id = vm_id; + ffa_dev = ffa_device_register(&buf, &ffa_drv_ops); + if (!ffa_dev) { + pr_err("%s: failed to register host partition ID 0x%x\n", + __func__, vm_id); + return -EINVAL; + } + + ret = ffa_xa_add_partition_info(ffa_dev); + if (ret) + return ret; + + if (ffa_notifications_disabled()) + return 0; + + ret = ffa_sched_recv_cb_update(ffa_dev, ffa_self_notif_handle, + drv_info, true); + if (ret) + pr_info("Failed to register driver sched callback %d\n", ret); return ret; } static void ffa_partitions_cleanup(void) { - struct ffa_dev_part_info *info; + struct list_head *phead; unsigned long idx; /* Clean up/free all registered devices */ ffa_devices_unregister(); - xa_for_each(&drv_info->partition_info, idx, info) { + xa_for_each(&drv_info->partition_info, idx, phead) { + struct ffa_dev_part_info *info, *tmp; + xa_erase(&drv_info->partition_info, idx); - kfree(info); + list_for_each_entry_safe(info, tmp, phead, node) { + list_del(&info->node); + kfree(info); + } + kfree(phead); } xa_destroy(&drv_info->partition_info); @@ -1621,7 +1701,7 @@ static int ffa_setup_partitions(void) !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) ffa_mode_32bit_set(ffa_dev); - if (ffa_xa_add_partition_info(ffa_dev->vm_id)) { + if (ffa_xa_add_partition_info(ffa_dev)) { ffa_device_unregister(ffa_dev); continue; } @@ -1629,12 +1709,16 @@ static int ffa_setup_partitions(void) kfree(pbuf); - /* Check if the host is already added as part of partition info */ + /* + * Check if the host is already added as part of partition info + * No multiple UUID possible for the host, so just checking if + * there is an entry will suffice + */ if (xa_load(&drv_info->partition_info, drv_info->vm_id)) return 0; /* Allocate for the host */ - ret = ffa_xa_add_partition_info(drv_info->vm_id); + ret = ffa_setup_host_partition(drv_info->vm_id); if (ret) ffa_partitions_cleanup(); @@ -1943,19 +2027,10 @@ static int __init ffa_init(void) ffa_notifications_setup(); ret = ffa_setup_partitions(); - if (ret) { - pr_err("failed to setup partitions\n"); - goto cleanup_notifs; - } + if (!ret) + return ret; - ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, - drv_info, true); - if (ret) - pr_info("Failed to register driver sched callback %d\n", ret); - - return 0; - -cleanup_notifs: + pr_err("failed to setup partitions\n"); ffa_notifications_cleanup(); free_pages: if (drv_info->tx_buffer) From 9472fe20d3968743e683bd48dace02b4accd7736 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 17 Feb 2025 15:39:00 +0000 Subject: [PATCH 19/23] firmware: arm_ffa: Handle ffa_notification_get correctly at virtual FF-A instance Currently it is assumed that the driver always calls ffa_notification_get() at the NS physical FF-A instance to request the SPMC to return pending SP or SPM Framework notifications. However, in order to support the driver invoking ffa_notification_get() at virtual FF-A instance, we need to make sure correct bits are enabled in the bitmaps enable flag. It is expected to have hypervisor framework and VM notifications bitmap to be zero at the non-secure physical FF-A instance. Message-Id: <20250217-ffa_updates-v3-19-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index db6334f0c532..f3ca703a4441 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -841,8 +841,12 @@ enum notify_type { #define NON_SECURE_VM_BITMAP_ENABLE BIT(NON_SECURE_VM) #define SPM_FRAMEWORK_BITMAP_ENABLE BIT(SPM_FRAMEWORK) #define NS_HYP_FRAMEWORK_BITMAP_ENABLE BIT(NS_HYP_FRAMEWORK) -#define FFA_BITMAP_ENABLE_MASK \ +#define FFA_BITMAP_SECURE_ENABLE_MASK \ (SECURE_PARTITION_BITMAP_ENABLE | SPM_FRAMEWORK_BITMAP_ENABLE) +#define FFA_BITMAP_NS_ENABLE_MASK \ + (NON_SECURE_VM_BITMAP_ENABLE | NS_HYP_FRAMEWORK_BITMAP_ENABLE) +#define FFA_BITMAP_ALL_ENABLE_MASK \ + (FFA_BITMAP_SECURE_ENABLE_MASK | FFA_BITMAP_NS_ENABLE_MASK) #define FFA_SECURE_PARTITION_ID_FLAG BIT(15) @@ -914,9 +918,15 @@ static int ffa_notification_get(u32 flags, struct ffa_notify_bitmaps *notify) else if (ret.a0 != FFA_SUCCESS) return -EINVAL; /* Something else went wrong. */ - notify->sp_map = PACK_NOTIFICATION_BITMAP(ret.a2, ret.a3); - notify->vm_map = PACK_NOTIFICATION_BITMAP(ret.a4, ret.a5); - notify->arch_map = PACK_NOTIFICATION_BITMAP(ret.a6, ret.a7); + if (flags & SECURE_PARTITION_BITMAP_ENABLE) + notify->sp_map = PACK_NOTIFICATION_BITMAP(ret.a2, ret.a3); + if (flags & NON_SECURE_VM_BITMAP_ENABLE) + notify->vm_map = PACK_NOTIFICATION_BITMAP(ret.a4, ret.a5); + if (flags & SPM_FRAMEWORK_BITMAP_ENABLE) + notify->arch_map = SPM_FRAMEWORK_BITMAP(ret.a6); + if (flags & NS_HYP_FRAMEWORK_BITMAP_ENABLE) + notify->arch_map = PACK_NOTIFICATION_BITMAP(notify->arch_map, + ret.a7); return 0; } @@ -1444,12 +1454,19 @@ static void handle_fwk_notif_callbacks(u32 bitmap) kfree(buf); } -static void notif_get_and_handle(void *unused) +static void notif_get_and_handle(void *cb_data) { int rc; - struct ffa_notify_bitmaps bitmaps; + u32 flags; + struct ffa_drv_info *info = cb_data; + struct ffa_notify_bitmaps bitmaps = { 0 }; - rc = ffa_notification_get(FFA_BITMAP_ENABLE_MASK, &bitmaps); + if (info->vm_id == 0) /* Non secure physical instance */ + flags = FFA_BITMAP_SECURE_ENABLE_MASK; + else + flags = FFA_BITMAP_ALL_ENABLE_MASK; + + rc = ffa_notification_get(flags, &bitmaps); if (rc) { pr_err("Failed to retrieve notifications with %d!\n", rc); return; From cecf6a504137aa238d768ae440a1f6488cb2f436 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 21 Feb 2025 09:56:31 +0000 Subject: [PATCH 20/23] firmware: arm_ffa: Explicitly cast return value from FFA_VERSION before comparison The return value ver.a0 is unsigned long type and FFA_RET_NOT_SUPPORTED is a negative value. Since the return value from the firmware can be just 32-bit even on 64-bit systems as FFA specification mentions it as int32 error code in w0 register, explicitly casting to s32 ensures correct sign interpretation when comparing against a signed error code FFA_RET_NOT_SUPPORTED. Without casting, comparison between unsigned long and a negative constant could lead to unintended results due to type promotions. Fixes: 3bbfe9871005 ("firmware: arm_ffa: Add initial Arm FFA driver support") Reported-by: Andrei Homescu Message-Id: <20250221095633.506678-1-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index f3ca703a4441..7c288ae74f97 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -144,7 +144,7 @@ static int ffa_version_check(u32 *version) .a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION, }, &ver); - if (ver.a0 == FFA_RET_NOT_SUPPORTED) { + if ((s32)ver.a0 == FFA_RET_NOT_SUPPORTED) { pr_info("FFA_VERSION returned not supported\n"); return -EOPNOTSUPP; } From 3e282f41585c4dd49b688bd6395fd6f21a57c9f7 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 21 Feb 2025 09:56:32 +0000 Subject: [PATCH 21/23] firmware: arm_ffa: Explicitly cast return value from NOTIFICATION_INFO_GET The return value ret.a2 is of type unsigned long and FFA_RET_NO_DATA is a negative value. Since the return value from the firmware can be just 32-bit even on 64-bit systems as FFA specification mentions it as int32 error code in w0 register, explicitly casting to s32 ensures correct sign interpretation when comparing against a signed error code FFA_RET_NO_DATA. Without casting, comparison between unsigned long and a negative constant could lead to unintended results due to type promotions. Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") Reported-by: Andrei Homescu Message-Id: <20250221095633.506678-2-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 7c288ae74f97..37305f37132c 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -976,7 +976,7 @@ static void ffa_notification_info_get(void) }, &ret); if (ret.a0 != FFA_FN_NATIVE(SUCCESS) && ret.a0 != FFA_SUCCESS) { - if (ret.a2 != FFA_RET_NO_DATA) + if ((s32)ret.a2 != FFA_RET_NO_DATA) pr_err("Notification Info fetch failed: 0x%lx (0x%lx)", ret.a0, ret.a2); return; From c67c2332f8c80b03990914dfb66950c8d2fb87d8 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Sun, 23 Feb 2025 21:39:09 +0000 Subject: [PATCH 22/23] firmware: arm_ffa: Skip the first/partition ID when parsing vCPU list The FF-A notification id list received in response to the call FFA_NOTIFICATION_INFO_GET is encoded as: partition ID followed by 0 or more vCPU ID. The count includes all of them. Fix the issue by skipping the first/partition ID so that only the list of vCPU IDs are processed correctly for a given partition ID. The first/ partition ID is read before the start of the loop. Fixes: 3522be48d82b ("firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface") Reported-by: Andrei Homescu Message-Id: <20250223213909.1197786-1-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 37305f37132c..19295282de24 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1012,7 +1012,7 @@ static void ffa_notification_info_get(void) } /* Per vCPU Notification */ - for (idx = 0; idx < ids_count[list]; idx++) { + for (idx = 1; idx < ids_count[list]; idx++) { if (ids_processed >= max_ids - 1) break; From cc0aac7ca17e0ea3ca84b552fc79f3e86fd07f53 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 17 Jan 2025 15:35:52 +0530 Subject: [PATCH 23/23] firmware: arm_ffa: Set dma_mask for ffa devices Set dma_mask for FFA devices, otherwise DMA allocation using the device pointer lead to following warning: WARNING: CPU: 1 PID: 1 at kernel/dma/mapping.c:597 dma_alloc_attrs+0xe0/0x124 Signed-off-by: Viresh Kumar Message-Id: Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index 98118823cf84..50bfe56c755e 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -212,6 +212,7 @@ ffa_device_register(const struct ffa_partition_info *part_info, dev = &ffa_dev->dev; dev->bus = &ffa_bus_type; dev->release = ffa_release_device; + dev->dma_mask = &dev->coherent_dma_mask; dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); ffa_dev->id = id;