Arm SCMI/FF-A fixes for v7.2

Fix two runtime issues in the SCMI framework. Use full 64-bit division
 when rounding range-based clock rates, avoiding divisor truncation and
 a possible divide-by-zero on 32-bit systems. Rate-limit notification
 queue-full warnings emitted from interrupt context to prevent printk
 floods and prolonged system stalls during notification bursts. Also
 correct a grammar error in the ARM_SCMI_POWER_CONTROL Kconfig help
 text.
 
 Fix the FF-A driver RX/TX buffer sizing logic to respect the maximum
 buffer size advertised by firmware, while retaining compatibility with
 older implementations that may reject PAGE_SIZE-rounded buffers.
 Also fix a NULL pointer dereference in ffa_partition_info_get() by
 rejecting NULL UUID strings before passing them to uuid_parse().
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmpUwQAACgkQAEG6vDF+
 4pgbkA//Vi8kcHJvXynbr4doRmZwGn2tpK5+Rn921xJ8zWDIB3GgCkkLqGEm0KFm
 vg9KCi3dgXg3w2uM1DN+exPQlmxHmfHJtODiQyRUx7xwuWLUCEt/JqD8FUi1KIUL
 0uwtizWj/QTKvioHnZqNOLPbwLn+PGn6E4LE3d7YYvaISnB9gtp68Fkxn+88W1ry
 guSHNErlaPdyLGLmhh2vCfKz+uWIh2X6ie1IxpLLri1QvlUHupAtOlyhvncWeeaO
 abBDURuniqP5ol9jLcKrkybshXNo/Nq/VYFgESp72VqkUu5Mccm7/3q9qm3UqOkl
 t9JKFyj/ytHgt+A6H5A3ju02Yujw7JrTP/Ql6rwBfanbuC4tT1hb28VHMEd0ocs1
 uDql+bwIDdmGsoM8W9TxKl3PHGjIK7a8vamaOaKFlXCT3jHAdVoP1a8liC8HmiAq
 9u3U86bWbE19U3HlqxDCPS4EO5oug8VJG/YXdUkR3jYOtEbwFk4IIeI/Fx/F8rUc
 rowSak9u63kg26rfeg5DX3gh+O/9z7cSnefHyYrXi3r+AR0jg396In6eKXG9AJRQ
 2g1WjJdj+1UjQrU9rIPURqmMeasZa3o6c4mKpCoUVNbu1sz+elZM2RqhzpFX5V0N
 EJcGDnnqEK0Ply2YQ1UxIvnLRkRt62ZCp5/9tbGoYD/avOPtULc=
 =J0zR
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmpX8usACgkQmmx57+YA
 GNlwNQ/8Cel80xEVfhAQ9VXAuSTh+8JmGVoPH+COJpvVm38KcDy3d7FB/B5USpIk
 X3s7fjx9CCc67d2nv4n95JJ19Sj+Ml/sWJnfOsaFeZGSQrow04r6Pko1h4kBxFCG
 d/oWhq/EWKCxy1mdIkf6EjePQJAHOq0/NxPZuRGz2RQH6K42/otaP+RKGN0eXQqK
 hpmD9RPEiVBl7rpe0oF/AiUikRsDdbAvjiVG2wHaDVpNoq53u5WcaeHx2RxRtuV+
 2hsmVJ/kSrh4INotcMfE/fNolwW/FRdXsh4VHqo2rt6toF04puUVOMNiaVYtua71
 AAoXvQG1x9VNfo8fUYwllHawDFtV66oyUSO6Jr1cUWXiN09PV9Qd18fWI0ncFa5b
 oGD8l54XsiCvKZzB4XbKPzrSPc3egbUD6o9nPb8G4XlEORPVaqa5U2l9mEuNgjc1
 cdjuJU6zHu0plDSvZX3dQ9nLboP4k8jO08tgUaeKPX65Ol2lmOjR0u3/CakkaNQe
 fgEE6b0tYDNthplgN/rXJrG8D3JrysTQv1XaB1GCPIdBi/WnTkwKbwGJweygxvIL
 lmdq0apLM2cLzf7tEtXrBvoavHy7j7Os580hc9LllJHoz6jyK5I2vv48bxCkgDms
 xcky6OCfnD71jN0sLYIeCuhI8CR+5UvmeoW9V9TioFB7qKo1I68=
 =BUNp
 -----END PGP SIGNATURE-----

Merge tag 'scmi-ffa-fixes-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes

Arm SCMI/FF-A fixes for v7.2

Fix two runtime issues in the SCMI framework. Use full 64-bit division
when rounding range-based clock rates, avoiding divisor truncation and
a possible divide-by-zero on 32-bit systems. Rate-limit notification
queue-full warnings emitted from interrupt context to prevent printk
floods and prolonged system stalls during notification bursts. Also
correct a grammar error in the ARM_SCMI_POWER_CONTROL Kconfig help
text.

Fix the FF-A driver RX/TX buffer sizing logic to respect the maximum
buffer size advertised by firmware, while retaining compatibility with
older implementations that may reject PAGE_SIZE-rounded buffers.
Also fix a NULL pointer dereference in ffa_partition_info_get() by
rejecting NULL UUID strings before passing them to uuid_parse().

* tag 'scmi-ffa-fixes-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Rate-limit queue-full warnings in IRQ context
  firmware: arm_scmi: Use 64-bit division for clock rate rounding
  firmware: arm_scmi: Grammar s/may needed/may be needed/
  firmware: arm_ffa: Fix NULL dereference in ffa_partition_info_get()
  firmware: arm_ffa: Respect firmware advertised RX/TX buffer size limits

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2026-07-15 22:50:24 +02:00
commit add11ea55f
4 changed files with 34 additions and 18 deletions

View File

@ -32,6 +32,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@ -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
@ -1139,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;
}
@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}