From 53716a4d745f1dac7aff33f3d1494b701eb2f888 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Tue, 2 Jun 2026 21:54:06 +0000 Subject: [PATCH 1/5] firmware: arm_ffa: Respect firmware advertised RX/TX buffer size limits FFA_FEATURES reports the minimum size and alignment boundary required for RXTX_MAP. In FF-A v1.2 and later it can also report a maximum buffer size, with zero meaning that no maximum is enforced. The driver only used the minimum value and then rounded it up to PAGE_SIZE before invoking RXTX_MAP after commit 83210251fd70 ("firmware: arm_ffa: Use the correct buffer size during RXTX_MAP"). On systems where PAGE_SIZE is larger than the advertised minimum, this can exceed a non-zero maximum reported by firmware. Older implementations do not advertise a maximum and may also reject the rounded-up size. Decode the maximum size and clamp the page-aligned minimum to it when it is present. If no maximum is advertised and RXTX_MAP rejects the rounded size with INVALID_PARAMETERS, retry with the advertised minimum size. Record drv_info->rxtx_bufsz only after RXTX_MAP succeeds so it reflects the size registered with firmware. While there, also update RXTX_MAP_MIN_BUFSZ() to use FIELD_GET() for consistency. Fixes: 83210251fd70 ("firmware: arm_ffa: Use the correct buffer size during RXTX_MAP") Suggested-by: Sudeep Holla Signed-off-by: Seth Forshee Link: https://patch.msgid.link/20260602-b4-ffa-rxtx-map-fixes-v2-1-7cb06508da84@nvidia.com (sudeep.holla: Minor rewording subject and commit message) Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 0f468362c288..bc2685331b27 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,9 @@ (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) #define RXTX_MAP_MIN_BUFSZ_MASK GENMASK(1, 0) -#define RXTX_MAP_MIN_BUFSZ(x) ((x) & RXTX_MAP_MIN_BUFSZ_MASK) +#define RXTX_MAP_MAX_BUFSZ_MASK GENMASK(31, 16) +#define RXTX_MAP_MIN_BUFSZ(x) (FIELD_GET(RXTX_MAP_MIN_BUFSZ_MASK, (x))) +#define RXTX_MAP_MAX_BUFSZ(x) (FIELD_GET(RXTX_MAP_MAX_BUFSZ_MASK, (x))) #define FFA_MAX_NOTIFICATIONS 64 @@ -2101,7 +2104,7 @@ static int ffa_probe(struct platform_device *pdev) { int ret; u32 buf_sz; - size_t rxtx_bufsz = SZ_4K; + size_t rxtx_min_bufsz = SZ_4K, rxtx_max_bufsz = 0, rxtx_bufsz; if (IS_BUILTIN(CONFIG_ARM_FFA_TRANSPORT) && is_protected_kvm_enabled() && !is_pkvm_initialized()) @@ -2132,15 +2135,18 @@ static int ffa_probe(struct platform_device *pdev) ret = ffa_features(FFA_FN_NATIVE(RXTX_MAP), 0, &buf_sz, NULL); if (!ret) { if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 1) - rxtx_bufsz = SZ_64K; + rxtx_min_bufsz = SZ_64K; else if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 2) - rxtx_bufsz = SZ_16K; + rxtx_min_bufsz = SZ_16K; else - rxtx_bufsz = SZ_4K; + rxtx_min_bufsz = SZ_4K; + + rxtx_max_bufsz = RXTX_MAP_MAX_BUFSZ(buf_sz) * SZ_4K; + if (rxtx_max_bufsz != 0 && rxtx_max_bufsz < rxtx_min_bufsz) + rxtx_max_bufsz = rxtx_min_bufsz; } - rxtx_bufsz = PAGE_ALIGN(rxtx_bufsz); - drv_info->rxtx_bufsz = rxtx_bufsz; + rxtx_bufsz = min_not_zero(PAGE_ALIGN(rxtx_min_bufsz), rxtx_max_bufsz); drv_info->rx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL); if (!drv_info->rx_buffer) { ret = -ENOMEM; @@ -2156,10 +2162,17 @@ static int ffa_probe(struct platform_device *pdev) ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), virt_to_phys(drv_info->rx_buffer), rxtx_bufsz / FFA_PAGE_SIZE); + if (ret == -EINVAL && !rxtx_max_bufsz && rxtx_min_bufsz < rxtx_bufsz) { + rxtx_bufsz = rxtx_min_bufsz; + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), + rxtx_bufsz / FFA_PAGE_SIZE); + } if (ret) { pr_err("failed to register FFA RxTx buffers\n"); goto free_pages; } + drv_info->rxtx_bufsz = rxtx_bufsz; mutex_init(&drv_info->rx_lock); mutex_init(&drv_info->tx_lock); From 8ae5f8e4836667fcaffdf2e3c6068b0a8b364dd8 Mon Sep 17 00:00:00 2001 From: Unnathi Chalicheemala Date: Wed, 17 Jun 2026 16:35:00 -0700 Subject: [PATCH 2/5] firmware: arm_ffa: Fix NULL dereference in ffa_partition_info_get() ffa_partition_info_get() passes uuid_str directly to uuid_parse() without a NULL check. When a caller passes NULL, uuid_parse() -> __uuid_parse() -> uuid_is_valid() dereferences the pointer, causing a kernel panic: | Unable to handle kernel NULL pointer dereference at virtual address | 0000000000000040 | pc : uuid_parse+0x40/0xac | lr : ffa_partition_info_get+0x1c/0x94 [arm_ffa] Add a NULL guard before uuid_parse() so a NULL argument returns -ENODEV instead of crashing. Callers are expected to always supply a valid partition UUID, so NULL is not a supported input. Fixes: d0c0bce83122 ("firmware: arm_ffa: Setup in-kernel users of FFA partitions") Signed-off-by: Unnathi Chalicheemala Link: https://patch.msgid.link/20260617-ffa_partition_nullptr_fix-v2-1-bc801b4ce34c@oss.qualcomm.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 bc2685331b27..d475ff83132d 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1142,7 +1142,7 @@ static int ffa_partition_info_get(const char *uuid_str, uuid_t uuid; struct ffa_partition_info *pbuf; - if (uuid_parse(uuid_str, &uuid)) { + if (!uuid_str || uuid_parse(uuid_str, &uuid)) { pr_err("invalid uuid (%s)\n", uuid_str); return -ENODEV; } From 05e5ffde9b666ee6d3ec225efeda9c038fa74ac8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 3 Jun 2026 17:17:51 +0200 Subject: [PATCH 3/5] firmware: arm_scmi: Grammar s/may needed/may be needed/ Fix grammar in the help text for the ARM_SCMI_POWER_CONTROL symbol. Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/5180d04abfb8e3074a321e2eb73bacfdd61c30c5.1780499850.git.geert+renesas@glider.be Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index e3fb36825978..783c24a20e29 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -96,7 +96,7 @@ config ARM_SCMI_POWER_CONTROL firmware. This driver can also be built as a module. If so, the module will be - called scmi_power_control. Note this may needed early in boot to catch - early shutdown/reboot SCMI requests. + called scmi_power_control. Note this may be needed early in boot to + catch early shutdown/reboot SCMI requests. endmenu From bf1deecccf210d1dd84e85cd4a45070888583984 Mon Sep 17 00:00:00 2001 From: Steve Dunnagan Date: Wed, 1 Jul 2026 15:59:20 -0400 Subject: [PATCH 4/5] firmware: arm_scmi: Use 64-bit division for clock rate rounding SCMI clock range descriptors report rates as 64-bit values. When handling a range clock, scmi_clock_determine_rate() rounds the requested rate up to the next supported step using the SCMI RATE_STEP value. The current code uses div64_ul() for this calculation. Since div64_ul() takes an unsigned long divisor, the 64-bit RATE_STEP value can be truncated on 32-bit builds. In the worst case, a non-zero 64-bit step can be narrowed to zero before the division. Store RATE_STEP in a u64, reject a malformed zero step, and use DIV64_U64_ROUND_UP() so the divisor is handled as a 64-bit value. This does not change behavior for valid firmware reporting a non-zero step that fits in unsigned long. Tested on Xunlong Orange Pi 5 Plus / RK3588 with SCMI over SMC. SCMI clocks probed successfully before and after the change. SCMI-backed CPU clocks were exercised through cpufreq-dt by switching each CPU policy between its lowest and highest available OPP. Fixes: ecde921eb460 ("firmware: arm_scmi: Add clock determine_rate operation") Signed-off-by: Steve Dunnagan Link: https://patch.msgid.link/20260701195923.444270-1-sdunnaga@redhat.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/clock.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 42e666a628c7..0278705d809e 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -718,7 +718,7 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph, static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph, u32 clk_id, unsigned long *rate) { - u64 fmin, fmax, ftmp; + u64 fmin, fmax, ftmp, step; struct scmi_clock_info *clk; struct scmi_clock_desc *clkd; struct clock_info *ci = ph->get_priv(ph); @@ -749,11 +749,14 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph, return 0; } - ftmp = *rate - fmin; - ftmp += clkd->r.rates[RATE_STEP] - 1; /* to round up */ - ftmp = div64_ul(ftmp, clkd->r.rates[RATE_STEP]); + step = clkd->r.rates[RATE_STEP]; + if (!step) + return -EINVAL; - *rate = ftmp * clkd->r.rates[RATE_STEP] + fmin; + ftmp = *rate - fmin; + ftmp = DIV64_U64_ROUND_UP(ftmp, step); + + *rate = ftmp * step + fmin; return 0; } From a4447c0693830d5ecadd6e755cb7fdc55d86aacc Mon Sep 17 00:00:00 2001 From: Pushpendra Singh Date: Wed, 8 Jul 2026 12:53:39 +0530 Subject: [PATCH 5/5] firmware: arm_scmi: Rate-limit queue-full warnings in IRQ context The scmi_notify() function is called from interrupt context to queue received notification events onto a per-protocol kfifo. When the kfifo is full, it logs a warning via dev_warn() for every dropped event. Under conditions where the platform sends a burst of SCMI notifications faster than the deferred worker can drain the queue, this results in a flood of dev_warn() calls from IRQ context. Each call acquires the console lock and may execute blocking console writes, causing the CPU to be held in interrupt context for an extended period and leading to observable system stalls. Fix this by switching to dev_warn_ratelimited() to limit the frequency of log messages when the notification queue is full. This reduces console overhead in interrupt context and prevents CPU stalls caused by excessive logging, while still preserving diagnostic visibility. Fixes: bd31b249692e ("firmware: arm_scmi: Add notification dispatch and delivery") Signed-off-by: Pushpendra Singh Link: https://patch.msgid.link/20260708072339.3021140-1-pushpendra.singh@oss.qualcomm.com Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/notify.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index 40ec184eedae..0a192cf2deab 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -600,9 +600,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id, return -EINVAL; } if (kfifo_avail(&r_evt->proto->equeue.kfifo) < sizeof(eh) + len) { - dev_warn(handle->dev, - "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n", - proto_id, evt_id, ktime_to_ns(ts)); + dev_warn_ratelimited(handle->dev, + "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n", + proto_id, evt_id, ktime_to_ns(ts)); return -ENOMEM; }