Skip to content

Commit 9a5d769

Browse files
committed
Merge tag 'ffa-fixes-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes
Arm FF-A fixes for v6.16 Couple of fixes to address: 1. The safety and memory issues in the FF-A notification callback handler: The fixes replaces a mutex with an rwlock to prevent sleeping in atomic context, resolving kernel warnings. Memory allocation is moved outside the lock to support this transition safely. Additionally, a memory leak in the notifier unregistration path is fixed by properly freeing the callback node. 2. The missing entry in struct ffa_indirect_msg_hdr: The fix adds the missing 32 bit reserved entry in the structure as required by the FF-A specification. * tag 'ffa-fixes-6.16' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_ffa: Fix the missing entry in struct ffa_indirect_msg_hdr firmware: arm_ffa: Replace mutex with rwlock to avoid sleep in atomic context firmware: arm_ffa: Move memory allocation outside the mutex locking firmware: arm_ffa: Fix memory leak by freeing notifier callback node Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 86731a2 + 4c46a47 commit 9a5d769

File tree

2 files changed

+37
-35
lines changed

2 files changed

+37
-35
lines changed

drivers/firmware/arm_ffa/driver.c

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ struct ffa_drv_info {
110110
struct work_struct sched_recv_irq_work;
111111
struct xarray partition_info;
112112
DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
113-
struct mutex notify_lock; /* lock to protect notifier hashtable */
113+
rwlock_t notify_lock; /* lock to protect notifier hashtable */
114114
};
115115

116116
static struct ffa_drv_info *drv_info;
@@ -1250,13 +1250,12 @@ notifier_hnode_get_by_type(u16 notify_id, enum notify_type type)
12501250
return NULL;
12511251
}
12521252

1253-
static int
1254-
update_notifier_cb(struct ffa_device *dev, int notify_id, void *cb,
1255-
void *cb_data, bool is_registration, bool is_framework)
1253+
static int update_notifier_cb(struct ffa_device *dev, int notify_id,
1254+
struct notifier_cb_info *cb, bool is_framework)
12561255
{
12571256
struct notifier_cb_info *cb_info = NULL;
12581257
enum notify_type type = ffa_notify_type_get(dev->vm_id);
1259-
bool cb_found;
1258+
bool cb_found, is_registration = !!cb;
12601259

12611260
if (is_framework)
12621261
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, dev->vm_id,
@@ -1270,20 +1269,10 @@ update_notifier_cb(struct ffa_device *dev, int notify_id, void *cb,
12701269
return -EINVAL;
12711270

12721271
if (is_registration) {
1273-
cb_info = kzalloc(sizeof(*cb_info), GFP_KERNEL);
1274-
if (!cb_info)
1275-
return -ENOMEM;
1276-
1277-
cb_info->dev = dev;
1278-
cb_info->cb_data = cb_data;
1279-
if (is_framework)
1280-
cb_info->fwk_cb = cb;
1281-
else
1282-
cb_info->cb = cb;
1283-
1284-
hash_add(drv_info->notifier_hash, &cb_info->hnode, notify_id);
1272+
hash_add(drv_info->notifier_hash, &cb->hnode, notify_id);
12851273
} else {
12861274
hash_del(&cb_info->hnode);
1275+
kfree(cb_info);
12871276
}
12881277

12891278
return 0;
@@ -1300,20 +1289,19 @@ static int __ffa_notify_relinquish(struct ffa_device *dev, int notify_id,
13001289
if (notify_id >= FFA_MAX_NOTIFICATIONS)
13011290
return -EINVAL;
13021291

1303-
mutex_lock(&drv_info->notify_lock);
1292+
write_lock(&drv_info->notify_lock);
13041293

1305-
rc = update_notifier_cb(dev, notify_id, NULL, NULL, false,
1306-
is_framework);
1294+
rc = update_notifier_cb(dev, notify_id, NULL, is_framework);
13071295
if (rc) {
13081296
pr_err("Could not unregister notification callback\n");
1309-
mutex_unlock(&drv_info->notify_lock);
1297+
write_unlock(&drv_info->notify_lock);
13101298
return rc;
13111299
}
13121300

13131301
if (!is_framework)
13141302
rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id));
13151303

1316-
mutex_unlock(&drv_info->notify_lock);
1304+
write_unlock(&drv_info->notify_lock);
13171305

13181306
return rc;
13191307
}
@@ -1334,35 +1322,48 @@ static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
13341322
{
13351323
int rc;
13361324
u32 flags = 0;
1325+
struct notifier_cb_info *cb_info = NULL;
13371326

13381327
if (ffa_notifications_disabled())
13391328
return -EOPNOTSUPP;
13401329

13411330
if (notify_id >= FFA_MAX_NOTIFICATIONS)
13421331
return -EINVAL;
13431332

1344-
mutex_lock(&drv_info->notify_lock);
1333+
cb_info = kzalloc(sizeof(*cb_info), GFP_KERNEL);
1334+
if (!cb_info)
1335+
return -ENOMEM;
1336+
1337+
cb_info->dev = dev;
1338+
cb_info->cb_data = cb_data;
1339+
if (is_framework)
1340+
cb_info->fwk_cb = cb;
1341+
else
1342+
cb_info->cb = cb;
1343+
1344+
write_lock(&drv_info->notify_lock);
13451345

13461346
if (!is_framework) {
13471347
if (is_per_vcpu)
13481348
flags = PER_VCPU_NOTIFICATION_FLAG;
13491349

13501350
rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags);
1351-
if (rc) {
1352-
mutex_unlock(&drv_info->notify_lock);
1353-
return rc;
1354-
}
1351+
if (rc)
1352+
goto out_unlock_free;
13551353
}
13561354

1357-
rc = update_notifier_cb(dev, notify_id, cb, cb_data, true,
1358-
is_framework);
1355+
rc = update_notifier_cb(dev, notify_id, cb_info, is_framework);
13591356
if (rc) {
13601357
pr_err("Failed to register callback for %d - %d\n",
13611358
notify_id, rc);
13621359
if (!is_framework)
13631360
ffa_notification_unbind(dev->vm_id, BIT(notify_id));
13641361
}
1365-
mutex_unlock(&drv_info->notify_lock);
1362+
1363+
out_unlock_free:
1364+
write_unlock(&drv_info->notify_lock);
1365+
if (rc)
1366+
kfree(cb_info);
13661367

13671368
return rc;
13681369
}
@@ -1406,9 +1407,9 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
14061407
if (!(bitmap & 1))
14071408
continue;
14081409

1409-
mutex_lock(&drv_info->notify_lock);
1410+
read_lock(&drv_info->notify_lock);
14101411
cb_info = notifier_hnode_get_by_type(notify_id, type);
1411-
mutex_unlock(&drv_info->notify_lock);
1412+
read_unlock(&drv_info->notify_lock);
14121413

14131414
if (cb_info && cb_info->cb)
14141415
cb_info->cb(notify_id, cb_info->cb_data);
@@ -1446,9 +1447,9 @@ static void handle_fwk_notif_callbacks(u32 bitmap)
14461447

14471448
ffa_rx_release();
14481449

1449-
mutex_lock(&drv_info->notify_lock);
1450+
read_lock(&drv_info->notify_lock);
14501451
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
1451-
mutex_unlock(&drv_info->notify_lock);
1452+
read_unlock(&drv_info->notify_lock);
14521453

14531454
if (cb_info && cb_info->fwk_cb)
14541455
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
@@ -1973,7 +1974,7 @@ static void ffa_notifications_setup(void)
19731974
goto cleanup;
19741975

19751976
hash_init(drv_info->notifier_hash);
1976-
mutex_init(&drv_info->notify_lock);
1977+
rwlock_init(&drv_info->notify_lock);
19771978

19781979
drv_info->notif_enabled = true;
19791980
return;

include/linux/arm_ffa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ struct ffa_indirect_msg_hdr {
283283
u32 offset;
284284
u32 send_recv_id;
285285
u32 size;
286+
u32 res1;
286287
uuid_t uuid;
287288
};
288289

0 commit comments

Comments
 (0)