Skip to content

Commit 176d23a

Browse files
committed
habanalabs: disable IRQ in user interrupts spinlock
Because this spinlock is taken in an interrupt handler, we must use the spin_lock_irqsave/irqrestore version to disable the interrupts on the local CPU. Otherwise, we can have a potential deadlock (if the interrupt handler is scheduled to run on the same cpu that the code who took the lock was running on). Signed-off-by: Oded Gabbay <[email protected]>
1 parent 7173109 commit 176d23a

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

drivers/misc/habanalabs/common/command_submission.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -923,13 +923,14 @@ static void
923923
wake_pending_user_interrupt_threads(struct hl_user_interrupt *interrupt)
924924
{
925925
struct hl_user_pending_interrupt *pend;
926+
unsigned long flags;
926927

927-
spin_lock(&interrupt->wait_list_lock);
928+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
928929
list_for_each_entry(pend, &interrupt->wait_list_head, wait_list_node) {
929930
pend->fence.error = -EIO;
930931
complete_all(&pend->fence.completion);
931932
}
932-
spin_unlock(&interrupt->wait_list_lock);
933+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
933934
}
934935

935936
void hl_release_pending_user_interrupts(struct hl_device *hdev)
@@ -2714,9 +2715,9 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27142715
{
27152716
struct hl_user_pending_interrupt *pend;
27162717
struct hl_user_interrupt *interrupt;
2717-
unsigned long timeout;
2718-
long completion_rc;
2718+
unsigned long timeout, flags;
27192719
u32 completion_value;
2720+
long completion_rc;
27202721
int rc = 0;
27212722

27222723
if (timeout_us == U32_MAX)
@@ -2739,7 +2740,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27392740
else
27402741
interrupt = &hdev->user_interrupt[interrupt_offset];
27412742

2742-
spin_lock(&interrupt->wait_list_lock);
2743+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
27432744
if (!hl_device_operational(hdev, NULL)) {
27442745
rc = -EPERM;
27452746
goto unlock_and_free_fence;
@@ -2765,7 +2766,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27652766
* handler to monitor
27662767
*/
27672768
list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head);
2768-
spin_unlock(&interrupt->wait_list_lock);
2769+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
27692770

27702771
wait_again:
27712772
/* Wait for interrupt handler to signal completion */
@@ -2777,12 +2778,12 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27772778
* If comparison fails, keep waiting until timeout expires
27782779
*/
27792780
if (completion_rc > 0) {
2780-
spin_lock(&interrupt->wait_list_lock);
2781+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
27812782

27822783
if (copy_from_user(&completion_value,
27832784
u64_to_user_ptr(user_address), 4)) {
27842785

2785-
spin_unlock(&interrupt->wait_list_lock);
2786+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
27862787

27872788
dev_err(hdev->dev,
27882789
"Failed to copy completion value from user\n");
@@ -2792,13 +2793,13 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27922793
}
27932794

27942795
if (completion_value >= target_value) {
2795-
spin_unlock(&interrupt->wait_list_lock);
2796+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
27962797
*status = CS_WAIT_STATUS_COMPLETED;
27972798
} else {
27982799
reinit_completion(&pend->fence.completion);
27992800
timeout = completion_rc;
28002801

2801-
spin_unlock(&interrupt->wait_list_lock);
2802+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
28022803
goto wait_again;
28032804
}
28042805
} else if (completion_rc == -ERESTARTSYS) {
@@ -2812,11 +2813,11 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
28122813
}
28132814

28142815
remove_pending_user_interrupt:
2815-
spin_lock(&interrupt->wait_list_lock);
2816+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
28162817
list_del(&pend->wait_list_node);
28172818

28182819
unlock_and_free_fence:
2819-
spin_unlock(&interrupt->wait_list_lock);
2820+
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
28202821
kfree(pend);
28212822
hl_ctx_put(ctx);
28222823

0 commit comments

Comments
 (0)