From 2b9c66d1abacbef91bdadc47fa8b9a3bd3a8fe99 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Thu, 11 Apr 2024 13:57:32 +0100 Subject: firmware: arm_ffa: Skip creation of the notification bitmaps When the FF-A driver is running inside a guest VM under an hypervisor, the driver/guest VM doesn't have the permission/capability to request the creation of notification bitmaps. For a VM, the hypervisor reserves memory for its VM and hypervisor framework notification bitmaps and the SPMC reserves memory for its SP and SPMC framework notification bitmaps before the hypervisor initializes it. The hypervisor does not initialize a VM if memory cannot be reserved for all its notification bitmaps. So the creation of all the necessary bitmaps are already done when the driver initialises and hence it can be skipped. We rely on FFA_FEATURES(FFA_NOTIFICATION_BITMAP_CREATE) to fail when running in the guest to handle this in the driver. Signed-off-by: Jens Wiklander Link: https://lore.kernel.org/r/20240411-ffa_npi_support-v2-1-927a670254e6@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index f2556a8e9401..a2818b69c8aa 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1442,17 +1442,15 @@ static void ffa_notifications_setup(void) int ret, irq; ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL); - if (ret) { - pr_info("Notifications not supported, continuing with it ..\n"); - return; - } + if (!ret) { + ret = ffa_notification_bitmap_create(); + if (ret) { + pr_err("Notification bitmap create error %d\n", ret); + return; + } - ret = ffa_notification_bitmap_create(); - if (ret) { - pr_info("Notification bitmap create error %d\n", ret); - return; + drv_info->bitmap_created = true; } - drv_info->bitmap_created = true; irq = ffa_sched_recv_irq_map(); if (irq <= 0) { -- cgit v1.2.3 From f936c242553febd5052c6178c1ac555adf837fec Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 11 Apr 2024 13:57:33 +0100 Subject: firmware: arm_ffa: Refactor SRI handling in prepartion to add NPI support In preparation to support handling of Notification Pending Interrupt(NPI) in addition to the existing support for Schedule Receiver Interrupt(SRI), refactor the code around SRI handling so that NPI support can reuse some of it. This change shouldn't have any functionality impact. It neither adds the support for NPIs nor changes any SRI support. Tested-by: Jens Wiklander Link: https://lore.kernel.org/r/20240411-ffa_npi_support-v2-2-927a670254e6@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 47 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index a2818b69c8aa..58cc017332c9 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -105,7 +105,7 @@ struct ffa_drv_info { struct ffa_pcpu_irq __percpu *irq_pcpu; struct workqueue_struct *notif_pcpu_wq; struct work_struct notif_pcpu_work; - struct work_struct irq_work; + struct work_struct sched_recv_irq_work; struct xarray partition_info; DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS)); struct mutex notify_lock; /* lock to protect notifier hashtable */ @@ -1291,12 +1291,12 @@ static void ffa_partitions_cleanup(void) #define FFA_FEAT_SCHEDULE_RECEIVER_INT (2) #define FFA_FEAT_MANAGED_EXIT_INT (3) -static irqreturn_t irq_handler(int irq, void *irq_data) +static irqreturn_t ffa_sched_recv_irq_handler(int irq, void *irq_data) { struct ffa_pcpu_irq *pcpu = irq_data; struct ffa_drv_info *info = pcpu->info; - queue_work(info->notif_pcpu_wq, &info->irq_work); + queue_work(info->notif_pcpu_wq, &info->sched_recv_irq_work); return IRQ_HANDLED; } @@ -1306,15 +1306,23 @@ static void ffa_sched_recv_irq_work_fn(struct work_struct *work) ffa_notification_info_get(); } -static int ffa_sched_recv_irq_map(void) +static int ffa_irq_map(u32 id) { - int ret, irq, sr_intid; + char *err_str; + int ret, irq, intid; - /* The returned sr_intid is assumed to be SGI donated to NS world */ - ret = ffa_features(FFA_FEAT_SCHEDULE_RECEIVER_INT, 0, &sr_intid, NULL); + if (id == FFA_FEAT_NOTIFICATION_PENDING_INT) + err_str = "Notification Pending Interrupt"; + else if (id == FFA_FEAT_SCHEDULE_RECEIVER_INT) + err_str = "Schedule Receiver Interrupt"; + else + err_str = "Unknown ID"; + + /* The returned intid is assumed to be SGI donated to NS world */ + ret = ffa_features(id, 0, &intid, NULL); if (ret < 0) { if (ret != -EOPNOTSUPP) - pr_err("Failed to retrieve scheduler Rx interrupt\n"); + pr_err("Failed to retrieve FF-A %s %u\n", err_str, id); return ret; } @@ -1329,12 +1337,12 @@ static int ffa_sched_recv_irq_map(void) oirq.np = gic; oirq.args_count = 1; - oirq.args[0] = sr_intid; + oirq.args[0] = intid; irq = irq_create_of_mapping(&oirq); of_node_put(gic); #ifdef CONFIG_ACPI } else { - irq = acpi_register_gsi(NULL, sr_intid, ACPI_EDGE_SENSITIVE, + irq = acpi_register_gsi(NULL, intid, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH); #endif } @@ -1347,12 +1355,11 @@ static int ffa_sched_recv_irq_map(void) return irq; } -static void ffa_sched_recv_irq_unmap(void) +static void ffa_irq_unmap(unsigned int irq) { - if (drv_info->sched_recv_irq) { - irq_dispose_mapping(drv_info->sched_recv_irq); - drv_info->sched_recv_irq = 0; - } + if (!irq) + return; + irq_dispose_mapping(irq); } static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu) @@ -1402,13 +1409,14 @@ static int ffa_init_pcpu_irq(unsigned int irq) drv_info->irq_pcpu = irq_pcpu; - ret = request_percpu_irq(irq, irq_handler, "ARM-FFA", irq_pcpu); + ret = request_percpu_irq(irq, ffa_sched_recv_irq_handler, "ARM-FFA-SRI", + irq_pcpu); if (ret) { pr_err("Error registering notification IRQ %d: %d\n", irq, ret); return ret; } - INIT_WORK(&drv_info->irq_work, ffa_sched_recv_irq_work_fn); + INIT_WORK(&drv_info->sched_recv_irq_work, ffa_sched_recv_irq_work_fn); INIT_WORK(&drv_info->notif_pcpu_work, notif_pcpu_irq_work_fn); drv_info->notif_pcpu_wq = create_workqueue("ffa_pcpu_irq_notification"); if (!drv_info->notif_pcpu_wq) @@ -1428,7 +1436,8 @@ static int ffa_init_pcpu_irq(unsigned int irq) static void ffa_notifications_cleanup(void) { ffa_uninit_pcpu_irq(); - ffa_sched_recv_irq_unmap(); + ffa_irq_unmap(drv_info->sched_recv_irq); + drv_info->sched_recv_irq = 0; if (drv_info->bitmap_created) { ffa_notification_bitmap_destroy(); @@ -1452,7 +1461,7 @@ static void ffa_notifications_setup(void) drv_info->bitmap_created = true; } - irq = ffa_sched_recv_irq_map(); + irq = ffa_irq_map(FFA_FEAT_SCHEDULE_RECEIVER_INT); if (irq <= 0) { ret = irq; goto cleanup; -- cgit v1.2.3 From 08530a2aa9214932a7e830f31af68881411c3335 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Thu, 11 Apr 2024 13:57:34 +0100 Subject: firmware: arm_ffa: Add support for handling notification pending interrupt(NPI) The FF-A uses the notification pending interrupt to inform the receiver that it has a pending notification. This is a virtual interrupt and is used by the following type of receivers: 1. A guest/VM running under a hypervisor. 2. An S-EL1 SP running under a S-EL2 SPMC. The rules that govern the properties of the NPI are the same as the rules for the SRI with couple of exceptions. Both SRI and NPI can be supported simultaneously. The handling of NPI is also same as the handling of notification for the self/primary VM with ID 0 except the absence of global notification. Signed-off-by: Jens Wiklander Link: https://lore.kernel.org/r/20240411-ffa_npi_support-v2-3-927a670254e6@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 71 ++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 16 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 58cc017332c9..018eddf40ca2 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -101,6 +101,7 @@ struct ffa_drv_info { bool bitmap_created; bool notif_enabled; unsigned int sched_recv_irq; + unsigned int notif_pend_irq; unsigned int cpuhp_state; struct ffa_pcpu_irq __percpu *irq_pcpu; struct workqueue_struct *notif_pcpu_wq; @@ -1301,6 +1302,15 @@ static irqreturn_t ffa_sched_recv_irq_handler(int irq, void *irq_data) return IRQ_HANDLED; } +static irqreturn_t notif_pend_irq_handler(int irq, void *irq_data) +{ + struct ffa_pcpu_irq *pcpu = irq_data; + + ffa_self_notif_handle(smp_processor_id(), true, pcpu->info); + + return IRQ_HANDLED; +} + static void ffa_sched_recv_irq_work_fn(struct work_struct *work) { ffa_notification_info_get(); @@ -1364,13 +1374,19 @@ static void ffa_irq_unmap(unsigned int irq) static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu) { - enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE); + if (drv_info->sched_recv_irq) + enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE); + if (drv_info->notif_pend_irq) + enable_percpu_irq(drv_info->notif_pend_irq, IRQ_TYPE_NONE); return 0; } static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu) { - disable_percpu_irq(drv_info->sched_recv_irq); + if (drv_info->sched_recv_irq) + disable_percpu_irq(drv_info->sched_recv_irq); + if (drv_info->notif_pend_irq) + disable_percpu_irq(drv_info->notif_pend_irq); return 0; } @@ -1389,13 +1405,16 @@ static void ffa_uninit_pcpu_irq(void) if (drv_info->sched_recv_irq) free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu); + if (drv_info->notif_pend_irq) + free_percpu_irq(drv_info->notif_pend_irq, drv_info->irq_pcpu); + if (drv_info->irq_pcpu) { free_percpu(drv_info->irq_pcpu); drv_info->irq_pcpu = NULL; } } -static int ffa_init_pcpu_irq(unsigned int irq) +static int ffa_init_pcpu_irq(void) { struct ffa_pcpu_irq __percpu *irq_pcpu; int ret, cpu; @@ -1409,11 +1428,26 @@ static int ffa_init_pcpu_irq(unsigned int irq) drv_info->irq_pcpu = irq_pcpu; - ret = request_percpu_irq(irq, ffa_sched_recv_irq_handler, "ARM-FFA-SRI", - irq_pcpu); - if (ret) { - pr_err("Error registering notification IRQ %d: %d\n", irq, ret); - return ret; + if (drv_info->sched_recv_irq) { + ret = request_percpu_irq(drv_info->sched_recv_irq, + ffa_sched_recv_irq_handler, + "ARM-FFA-SRI", irq_pcpu); + if (ret) { + pr_err("Error registering percpu SRI nIRQ %d : %d\n", + drv_info->sched_recv_irq, ret); + return ret; + } + } + + if (drv_info->notif_pend_irq) { + ret = request_percpu_irq(drv_info->notif_pend_irq, + notif_pend_irq_handler, + "ARM-FFA-NPI", irq_pcpu); + if (ret) { + pr_err("Error registering percpu NPI nIRQ %d : %d\n", + drv_info->notif_pend_irq, ret); + return ret; + } } INIT_WORK(&drv_info->sched_recv_irq_work, ffa_sched_recv_irq_work_fn); @@ -1438,6 +1472,8 @@ static void ffa_notifications_cleanup(void) ffa_uninit_pcpu_irq(); ffa_irq_unmap(drv_info->sched_recv_irq); drv_info->sched_recv_irq = 0; + ffa_irq_unmap(drv_info->notif_pend_irq); + drv_info->notif_pend_irq = 0; if (drv_info->bitmap_created) { ffa_notification_bitmap_destroy(); @@ -1448,7 +1484,7 @@ static void ffa_notifications_cleanup(void) static void ffa_notifications_setup(void) { - int ret, irq; + int ret; ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL); if (!ret) { @@ -1461,15 +1497,18 @@ static void ffa_notifications_setup(void) drv_info->bitmap_created = true; } - irq = ffa_irq_map(FFA_FEAT_SCHEDULE_RECEIVER_INT); - if (irq <= 0) { - ret = irq; - goto cleanup; - } + ret = ffa_irq_map(FFA_FEAT_SCHEDULE_RECEIVER_INT); + if (ret > 0) + drv_info->sched_recv_irq = ret; + + ret = ffa_irq_map(FFA_FEAT_NOTIFICATION_PENDING_INT); + if (ret > 0) + drv_info->notif_pend_irq = ret; - drv_info->sched_recv_irq = irq; + if (!drv_info->sched_recv_irq && !drv_info->notif_pend_irq) + goto cleanup; - ret = ffa_init_pcpu_irq(irq); + ret = ffa_init_pcpu_irq(); if (ret) goto cleanup; -- cgit v1.2.3 From 0370fb127ce3432a4081fe1415a947308cb827f1 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 18 Apr 2024 11:29:32 +0100 Subject: firmware: arm_ffa: Fix kernel warning about incorrect SRI/NPI If the firmware returns incorrect SRI/NRI number, we fail to set it up in the kernel which is absolutely fine. However, we don't reset the stashed value of sched_recv or notif_pend IRQs. When we call ffa_notifications_cleanup() in case of failures to setup the notifications, we end up calling free_percpu_irq() from ffa_uninit_pcpu_irq() which results in the following warning: | genirq: Flags mismatch irq 6. 00004401 (ARM-FFA-NPI) vs. 00004400 (IPI) | ARM FF-A: Error registering percpu NPI nIRQ 6 : -16 | ARM FF-A: Notification setup failed -16, not enabled | ------------[ cut here ]------------ | Trying to free already-free IRQ 6 | WARNING: CPU: 2 PID: 1 at kernel/irq/manage.c:2476 __free_percpu_irq+0x6c/0x138 | Modules linked in: | CPU: 2 PID: 1 Comm: swapper/0 Not tainted 6.9.0-rc3 #211 | Hardware name: FVP Base RevC (DT) | pstate: 614000c9 (nZCv daIF +PAN -UAO -TCO +DIT -SSBS BTYPE=--) | pc : __free_percpu_irq+0x6c/0x138 | lr : __free_percpu_irq+0x6c/0x138 | Call trace: | __free_percpu_irq+0x6c/0x138 | free_percpu_irq+0x48/0x84 | ffa_notifications_cleanup+0x78/0x164 | ffa_notifications_setup+0x368/0x3c0 | ffa_init+0x2b4/0x36c | do_one_initcall+0xe0/0x258 | do_initcall_level+0x8c/0xac | do_initcalls+0x54/0x94 | do_basic_setup+0x1c/0x28 | kernel_init_freeable+0x108/0x174 | kernel_init+0x20/0x1a4 | ret_from_fork+0x10/0x20 Fix the same by resetting the stashed copy of IRQ values to 0 in case of any failure to set them up properly. Cc: Jens Wiklander Link: https://lore.kernel.org/r/20240418102932.3093576-1-sudeep.holla@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 018eddf40ca2..b64e8ee64bc2 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1435,6 +1435,7 @@ static int ffa_init_pcpu_irq(void) if (ret) { pr_err("Error registering percpu SRI nIRQ %d : %d\n", drv_info->sched_recv_irq, ret); + drv_info->sched_recv_irq = 0; return ret; } } @@ -1446,6 +1447,7 @@ static int ffa_init_pcpu_irq(void) if (ret) { pr_err("Error registering percpu NPI nIRQ %d : %d\n", drv_info->notif_pend_irq, ret); + drv_info->notif_pend_irq = 0; return ret; } } -- cgit v1.2.3 From 3c258bf6bf29d8c9f9b358c64f6e9f4510c91ff9 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 17 Apr 2024 10:09:21 +0100 Subject: firmware: arm_ffa: Stash the partition properties for query purposes The properies obtained from the partition information descriptor as part of initial partitions discovery is useful as it contain info if the partition - Runs in AArch64 or AArch32 execution state - Can send and/or receive direct requests - Can send and receive indirect message - Does support receipt of notifications. These can be used for querying before attempting to do any of the above operations. Link: https://lore.kernel.org/r/20240417090921.2866447-1-sudeep.holla@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 ++ include/linux/arm_ffa.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index b64e8ee64bc2..99a23dd3d189 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1228,6 +1228,8 @@ static int ffa_setup_partitions(void) continue; } + ffa_dev->properties = tpbuf->properties; + if (drv_info->version > FFA_VERSION_1_0 && !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) ffa_mode_32bit_set(ffa_dev); diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index c906f666ff5d..94a49612ecec 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -126,6 +126,7 @@ /* FFA Bus/Device/Driver related */ struct ffa_device { u32 id; + u32 properties; int vm_id; bool mode_32bit; uuid_t uuid; @@ -221,12 +222,29 @@ struct ffa_partition_info { #define FFA_PARTITION_DIRECT_SEND BIT(1) /* partition can send and receive indirect messages. */ #define FFA_PARTITION_INDIRECT_MSG BIT(2) +/* partition can receive notifications */ +#define FFA_PARTITION_NOTIFICATION_RECV BIT(3) /* partition runs in the AArch64 execution state. */ #define FFA_PARTITION_AARCH64_EXEC BIT(8) u32 properties; u32 uuid[4]; }; +static inline +bool ffa_partition_check_property(struct ffa_device *dev, u32 property) +{ + return dev->properties & property; +} + +#define ffa_partition_supports_notify_recv(dev) \ + ffa_partition_check_property(dev, FFA_PARTITION_NOTIFICATION_RECV) + +#define ffa_partition_supports_indirect_msg(dev) \ + ffa_partition_check_property(dev, FFA_PARTITION_INDIRECT_MSG) + +#define ffa_partition_supports_direct_recv(dev) \ + ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_RECV) + /* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */ struct ffa_send_direct_data { unsigned long data0; /* w3/x3 */ -- cgit v1.2.3 From 02c19d84c7c5026624d181b8e4cdc8488134d013 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 17 Apr 2024 10:09:31 +0100 Subject: firmware: arm_ffa: Add support for FFA_MSG_SEND2 The FFA_MSG_SEND2 can be used to transmit a partition message from the Tx buffer of the sender(the driver in this case) endpoint to the Rx buffer of the receiver endpoint. An invocation of the FFA_MSG_SEND2 transfers the ownership of the Tx buffer to the receiver endpoint(or any intermediate consumer). Completion of an FFA_MSG_SEND2 invocation transfers the ownership of the buffer back to the sender endpoint. The framework defines the FFA_MSG_SEND2 interface to transmit a partition message from the Tx buffer of the sender to the Rx buffer of a receiver and inform the scheduler that the receiver must be run. Link: https://lore.kernel.org/r/20240417090931.2866487-1-sudeep.holla@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/arm_ffa.h | 9 +++++++++ 2 files changed, 47 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 99a23dd3d189..26968edac5b2 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -345,6 +345,38 @@ 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) +{ + u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); + struct ffa_indirect_msg_hdr *msg; + ffa_value_t ret; + int retval = 0; + + if (sz > (RXTX_BUFFER_SIZE - sizeof(*msg))) + return -ERANGE; + + mutex_lock(&drv_info->tx_lock); + + msg = drv_info->tx_buffer; + msg->flags = 0; + msg->res0 = 0; + msg->offset = sizeof(*msg); + msg->send_recv_id = src_dst_ids; + msg->size = sz; + memcpy(msg + msg->offset, buf, sz); + + /* flags = 0, sender VMID = 0 works for both physical/virtual NS */ + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_MSG_SEND2, .a1 = 0, .a2 = 0 + }, &ret); + + if (ret.a0 == FFA_ERROR) + retval = ffa_to_linux_errno((int)ret.a2); + + mutex_unlock(&drv_info->tx_lock); + return retval; +} + static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len, u32 len, u64 *handle) { @@ -871,6 +903,11 @@ static int ffa_sync_send_receive(struct ffa_device *dev, dev->mode_32bit, data); } +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_memory_share(struct ffa_mem_ops_args *args) { if (drv_info->mem_ops_native) @@ -1146,6 +1183,7 @@ static const struct ffa_info_ops ffa_drv_info_ops = { static const struct ffa_msg_ops ffa_drv_msg_ops = { .mode_32bit_set = ffa_mode_32bit_set, .sync_send_receive = ffa_sync_send_receive, + .indirect_send = ffa_indirect_msg_send, }; static const struct ffa_mem_ops ffa_drv_mem_ops = { diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index 94a49612ecec..c82d56768101 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -254,6 +254,14 @@ struct ffa_send_direct_data { unsigned long data4; /* w7/x7 */ }; +struct ffa_indirect_msg_hdr { + u32 flags; + u32 res0; + u32 offset; + u32 send_recv_id; + u32 size; +}; + struct ffa_mem_region_addr_range { /* The base IPA of the constituent memory region, aligned to 4 kiB */ u64 address; @@ -414,6 +422,7 @@ struct ffa_msg_ops { void (*mode_32bit_set)(struct ffa_device *dev); 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); }; struct ffa_mem_ops { -- cgit v1.2.3 From ddfade88f49d49b04930ae006ab0974eb547529c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Apr 2024 14:40:43 +0300 Subject: firmware: arm_ffa: Fix memory corruption in ffa_msg_send2() The "msg" pointer is a struct and msg->offset is the sizeof(*msg). The pointer here math means the memcpy() will write outside the bounds. Cast "msg" to a u8 pointer to fix this. Fixes: 02c19d84c7c5 ("firmware: arm_ffa: Add support for FFA_MSG_SEND2") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/cd5fb6b5-81fa-4a6d-b2b8-284ca704bbff@moroto.mountain Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 26968edac5b2..b29496cac2af 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -363,7 +363,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; - memcpy(msg + msg->offset, buf, sz); + memcpy((u8 *)msg + msg->offset, buf, sz); /* flags = 0, sender VMID = 0 works for both physical/virtual NS */ invoke_ffa_fn((ffa_value_t){ -- cgit v1.2.3 From 3a3e2b83e8059679e92be4273c601ea21e105a89 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 24 Apr 2024 14:16:40 +0100 Subject: firmware: arm_ffa: Avoid queuing work when running on the worker queue Currently notif_pcpu_irq_work_fn() may get queued from the work that is already running on the 'notif_pcpu_wq' workqueue. This may add unnecessary delays and could be avoided if the work is called directly instead. This change removes queuing of the work when already running on the 'notif_pcpu_wq' workqueue thereby removing any possible delays in that path. Link: https://lore.kernel.org/r/20240424131640.706870-1-sudeep.holla@arm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index b29496cac2af..78abde20ab01 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1146,7 +1146,7 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type) } } -static void notif_pcpu_irq_work_fn(struct work_struct *work) +static void notif_get_and_handle(void *unused) { int rc; struct ffa_notify_bitmaps bitmaps; @@ -1169,10 +1169,17 @@ ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data) struct ffa_drv_info *info = cb_data; if (!is_per_vcpu) - notif_pcpu_irq_work_fn(&info->notif_pcpu_work); + notif_get_and_handle(info); else - queue_work_on(vcpu, info->notif_pcpu_wq, - &info->notif_pcpu_work); + smp_call_function_single(vcpu, notif_get_and_handle, info, 0); +} + +static void notif_pcpu_irq_work_fn(struct work_struct *work) +{ + struct ffa_drv_info *info = container_of(work, struct ffa_drv_info, + notif_pcpu_work); + + ffa_self_notif_handle(smp_processor_id(), true, info); } static const struct ffa_info_ops ffa_drv_info_ops = { @@ -1345,8 +1352,10 @@ static irqreturn_t ffa_sched_recv_irq_handler(int irq, void *irq_data) static irqreturn_t notif_pend_irq_handler(int irq, void *irq_data) { struct ffa_pcpu_irq *pcpu = irq_data; + struct ffa_drv_info *info = pcpu->info; - ffa_self_notif_handle(smp_processor_id(), true, pcpu->info); + queue_work_on(smp_processor_id(), info->notif_pcpu_wq, + &info->notif_pcpu_work); return IRQ_HANDLED; } -- cgit v1.2.3