habanalabs: re-init completion object upon retry
authorOded Gabbay <ogabbay@kernel.org>
Thu, 1 Jul 2021 08:42:53 +0000 (11:42 +0300)
committerOded Gabbay <ogabbay@kernel.org>
Sun, 29 Aug 2021 06:47:45 +0000 (09:47 +0300)
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>
drivers/misc/habanalabs/common/command_submission.c

index 80c60fb41bbca5291cfade0a089fa5e544388fc3..12f20446e99a1f1bd62ef330e6a10c31495016a6 100644 (file)
@@ -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 {