Skip to content

Commit

Permalink
firmware: arm_ffa: Replace mutex with rwlock to avoid sleep in atomic…
Browse files Browse the repository at this point in the history
… context

The current use of a mutex to protect the notifier hashtable accesses
can lead to issues in the atomic context. It results in the below
kernel warnings:

  |  BUG: sleeping function called from invalid context at kernel/locking/mutex.c:258
  |  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 9, name: kworker/0:0
  |  preempt_count: 1, expected: 0
  |  RCU nest depth: 0, expected: 0
  |  CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.14.0 #4
  |  Workqueue: ffa_pcpu_irq_notification notif_pcpu_irq_work_fn
  |  Call trace:
  |   show_stack+0x18/0x24 (C)
  |   dump_stack_lvl+0x78/0x90
  |   dump_stack+0x18/0x24
  |   __might_resched+0x114/0x170
  |   __might_sleep+0x48/0x98
  |   mutex_lock+0x24/0x80
  |   handle_notif_callbacks+0x54/0xe0
  |   notif_get_and_handle+0x40/0x88
  |   generic_exec_single+0x80/0xc0
  |   smp_call_function_single+0xfc/0x1a0
  |   notif_pcpu_irq_work_fn+0x2c/0x38
  |   process_one_work+0x14c/0x2b4
  |   worker_thread+0x2e4/0x3e0
  |   kthread+0x13c/0x210
  |   ret_from_fork+0x10/0x20

To address this, replace the mutex with an rwlock to protect the notifier
hashtable accesses. This ensures that read-side locking does not sleep and
multiple readers can acquire the lock concurrently, avoiding unnecessary
contention and potential deadlocks. Writer access remains exclusive,
preserving correctness.

This change resolves warnings from lockdep about potential sleep in
atomic context.

Cc: Jens Wiklander <jens.wiklander@linaro.org>
Reported-by: Jérôme Forissier <jerome.forissier@linaro.org>
Closes: https://github.com/OP-TEE/optee_os/issues/7394
Fixes: e057344 ("firmware: arm_ffa: Add interfaces to request notification callbacks")
Message-Id: <20250528-ffa_notif_fix-v1-3-5ed7bc7f8437@arm.com>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Tested-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
  • Loading branch information
Sudeep Holla committed Jun 9, 2025
1 parent 27e850c commit 9ca7a42
Showing 1 changed file with 11 additions and 11 deletions.
22 changes: 11 additions & 11 deletions drivers/firmware/arm_ffa/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ struct ffa_drv_info {
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 */
rwlock_t notify_lock; /* lock to protect notifier hashtable */
};

static struct ffa_drv_info *drv_info;
Expand Down Expand Up @@ -1289,19 +1289,19 @@ static int __ffa_notify_relinquish(struct ffa_device *dev, int notify_id,
if (notify_id >= FFA_MAX_NOTIFICATIONS)
return -EINVAL;

mutex_lock(&drv_info->notify_lock);
write_lock(&drv_info->notify_lock);

rc = update_notifier_cb(dev, notify_id, NULL, is_framework);
if (rc) {
pr_err("Could not unregister notification callback\n");
mutex_unlock(&drv_info->notify_lock);
write_unlock(&drv_info->notify_lock);
return rc;
}

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

mutex_unlock(&drv_info->notify_lock);
write_unlock(&drv_info->notify_lock);

return rc;
}
Expand Down Expand Up @@ -1341,7 +1341,7 @@ static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
else
cb_info->cb = cb;

mutex_lock(&drv_info->notify_lock);
write_lock(&drv_info->notify_lock);

if (!is_framework) {
if (is_per_vcpu)
Expand All @@ -1361,7 +1361,7 @@ static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
}

out_unlock_free:
mutex_unlock(&drv_info->notify_lock);
write_unlock(&drv_info->notify_lock);
if (rc)
kfree(cb_info);

Expand Down Expand Up @@ -1407,9 +1407,9 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
if (!(bitmap & 1))
continue;

mutex_lock(&drv_info->notify_lock);
read_lock(&drv_info->notify_lock);
cb_info = notifier_hnode_get_by_type(notify_id, type);
mutex_unlock(&drv_info->notify_lock);
read_unlock(&drv_info->notify_lock);

if (cb_info && cb_info->cb)
cb_info->cb(notify_id, cb_info->cb_data);
Expand Down Expand Up @@ -1447,9 +1447,9 @@ static void handle_fwk_notif_callbacks(u32 bitmap)

ffa_rx_release();

mutex_lock(&drv_info->notify_lock);
read_lock(&drv_info->notify_lock);
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
mutex_unlock(&drv_info->notify_lock);
read_unlock(&drv_info->notify_lock);

if (cb_info && cb_info->fwk_cb)
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
Expand Down Expand Up @@ -1974,7 +1974,7 @@ static void ffa_notifications_setup(void)
goto cleanup;

hash_init(drv_info->notifier_hash);
mutex_init(&drv_info->notify_lock);
rwlock_init(&drv_info->notify_lock);

drv_info->notif_enabled = true;
return;
Expand Down

0 comments on commit 9ca7a42

Please sign in to comment.