mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user