summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorOded Gabbay <ogabbay@kernel.org>2021-07-01 11:42:53 +0300
committerOded Gabbay <ogabbay@kernel.org>2021-08-29 09:47:45 +0300
commitd5546d78ad409b90dbcb62100458875e8eaf6a0d (patch)
tree34f8be9f197808e6a5aac30f5737fd05acaa5ea2 /drivers/misc
parent82629c71c26c1a67a26b0b25971da97003c3b287 (diff)
downloadlinux-d5546d78ad409b90dbcb62100458875e8eaf6a0d.tar.xz
habanalabs: re-init completion object upon retry
In case user interrupt arrived but the completion value is less than the target value, we want to retry the wait. However, before the retry we must reinitialize the completion object, under spin-lock, so the wait function won't exit immediately because the completion object is already completed (from the previous interrupt). Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/habanalabs/common/command_submission.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c
index 80c60fb41bbc..12f20446e99a 100644
--- a/drivers/misc/habanalabs/common/command_submission.c
+++ b/drivers/misc/habanalabs/common/command_submission.c
@@ -2046,7 +2046,8 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
goto unlock_and_free_fence;
}
- if (copy_from_user(&completion_value, u64_to_user_ptr(user_address), 4)) {
+ if (copy_from_user(&completion_value, u64_to_user_ptr(user_address),
+ 4)) {
dev_err(hdev->dev,
"Failed to copy completion value from user\n");
rc = -EFAULT;
@@ -2077,18 +2078,28 @@ wait_again:
* If comparison fails, keep waiting until timeout expires
*/
if (completion_rc > 0) {
+ spin_lock(&interrupt->wait_list_lock);
+
if (copy_from_user(&completion_value,
u64_to_user_ptr(user_address), 4)) {
+
+ spin_unlock(&interrupt->wait_list_lock);
+
dev_err(hdev->dev,
"Failed to copy completion value from user\n");
rc = -EFAULT;
+
goto remove_pending_user_interrupt;
}
if (completion_value >= target_value) {
+ spin_unlock(&interrupt->wait_list_lock);
*status = CS_WAIT_STATUS_COMPLETED;
} else {
+ reinit_completion(&pend->fence.completion);
timeout = completion_rc;
+
+ spin_unlock(&interrupt->wait_list_lock);
goto wait_again;
}
} else {