habanalabs: take timestamp on wait for interrupt
authorYuri Nudelman <ynudelman@habana.ai>
Thu, 23 Sep 2021 14:40:14 +0000 (17:40 +0300)
committerOded Gabbay <ogabbay@kernel.org>
Mon, 18 Oct 2021 09:05:46 +0000 (12:05 +0300)
Taking an accurate timestamp in a close proximity of the interrupt is
required for user side statistics management.

Signed-off-by: Yuri Nudelman <ynudelman@habana.ai>
Reviewed-by: Oded Gabbay <ogabbay@kernel.org>
Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
drivers/misc/habanalabs/common/command_submission.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/irq.c

index 44bab01cd033992ae7a83e2c7233de04e2dfd3ea..4bc24852a2839a024a203839410a274d3de377a4 100644 (file)
@@ -2740,7 +2740,8 @@ static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data)
 static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
                                u32 timeout_us, u64 user_address,
                                u64 target_value, u16 interrupt_offset,
-                               enum hl_cs_wait_status *status)
+                               enum hl_cs_wait_status *status,
+                               bool take_timestamp, u64 *timestamp)
 {
        struct hl_user_pending_interrupt *pend;
        struct hl_user_interrupt *interrupt;
@@ -2764,6 +2765,8 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
 
        hl_fence_init(&pend->fence, ULONG_MAX);
 
+       pend->fence.take_timestamp = take_timestamp;
+
        if (interrupt_offset == HL_COMMON_USER_INTERRUPT_ID)
                interrupt = &hdev->common_user_interrupt;
        else
@@ -2838,6 +2841,8 @@ remove_pending_user_interrupt:
        list_del(&pend->wait_list_node);
        spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
 
+       *timestamp = ktime_to_ns(pend->fence.timestamp);
+
        kfree(pend);
        hl_ctx_put(ctx);
 
@@ -2851,6 +2856,7 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data)
        struct asic_fixed_properties *prop;
        union hl_wait_cs_args *args = data;
        enum hl_cs_wait_status status;
+       u64 timestamp;
        int rc;
 
        prop = &hdev->asic_prop;
@@ -2880,7 +2886,9 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data)
 
        rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx,
                                args->in.interrupt_timeout_us, args->in.addr,
-                               args->in.target, interrupt_offset, &status);
+                               args->in.target, interrupt_offset, &status,
+                               args->in.flags & HL_CS_FLAGS_TIMESTAMP,
+                               &timestamp);
 
        if (rc) {
                if (rc != -EINTR)
@@ -2892,6 +2900,11 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data)
 
        memset(args, 0, sizeof(*args));
 
+       if (timestamp) {
+               args->out.timestamp_nsec = timestamp;
+               args->out.flags |= HL_WAIT_CS_STATUS_FLAG_TIMESTAMP_VLD;
+       }
+
        switch (status) {
        case CS_WAIT_STATUS_COMPLETED:
                args->out.status = HL_WAIT_CS_STATUS_COMPLETED;
index 99de80915eed0945da637f0b9e5d1b08d1edb496..2d9edd734d1cce742c8afe24b8e8e4f418e86572 100644 (file)
@@ -601,6 +601,7 @@ struct asic_fixed_properties {
  *                         masters QIDs that multi cs is waiting on
  * @error: mark this fence with error
  * @timestamp: timestamp upon completion
+ * @take_timestamp: timestamp shall be taken upon completion
  */
 struct hl_fence {
        struct completion       completion;
@@ -609,6 +610,7 @@ struct hl_fence {
        u32                     stream_master_qid_map;
        int                     error;
        ktime_t                 timestamp;
+       u8                      take_timestamp;
 };
 
 /**
index 39b14a93339314feb8ee4b0b2903027515dfc4e8..0dd00ffd18094f9cab9fc441ff03771819bcc7f2 100644 (file)
@@ -143,8 +143,11 @@ static void handle_user_cq(struct hl_device *hdev,
        struct hl_user_pending_interrupt *pend;
 
        spin_lock(&user_cq->wait_list_lock);
-       list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node)
+       list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node) {
+               if (pend->fence.take_timestamp)
+                       pend->fence.timestamp = ktime_get();
                complete_all(&pend->fence.completion);
+       }
        spin_unlock(&user_cq->wait_list_lock);
 }