<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 2021-11-17 7:14 p.m., Felix Kuehling
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:71b8c251-97f3-3064-7861-d2bdb24b6ae9@amd.com">
      <br>
      On 2021-11-16 10:43 p.m., Philip Yang wrote:
      <br>
      <blockquote type="cite">unmap range always set
        svms->drain_pagefaults flag to simplify both
        <br>
        parent range and child range unmap. Deferred list work takes
        mmap write
        <br>
        lock to read and clear svms->drain_pagefaults, to serialize
        with unmap
        <br>
        callback.
        <br>
        <br>
        Add atomic flag svms->draining_faults, if
        svms->draining_faults is set,
        <br>
        page fault handle ignore the retry fault, to speed up interrupt
        handling.
        <br>
      </blockquote>
      Having both svms->drain_pagefaults and svms->draining_faults
      is confusing. Do we really need both?
    </blockquote>
    <p>Using one flag, I can not find a way to handle the case, unmap
      new range. if the flag is set, restore_pages uses the flag to drop
      fault, then drain_retry_fault reset the flag after draining is
      done, we will not able to drain retry fault for the new range.<br>
    </p>
    <p>Regards,</p>
    <p>Philip<br>
    </p>
    <blockquote type="cite" cite="mid:71b8c251-97f3-3064-7861-d2bdb24b6ae9@amd.com">Regards,
      <br>
        Felix
      <br>
      <br>
      <blockquote type="cite">
        <br>
        Signed-off-by: Philip Yang <a class="moz-txt-link-rfc2396E" href="mailto:Philip.Yang@amd.com"><Philip.Yang@amd.com></a>
        <br>
        ---
        <br>
          drivers/gpu/drm/amd/amdkfd/kfd_priv.h |  1 +
        <br>
          drivers/gpu/drm/amd/amdkfd/kfd_svm.c  | 24
        ++++++++++++++++++------
        <br>
          2 files changed, 19 insertions(+), 6 deletions(-)
        <br>
        <br>
        diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
        b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
        <br>
        index 1d3f012bcd2a..4e4640b731e1 100644
        <br>
        --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
        <br>
        +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
        <br>
        @@ -767,6 +767,7 @@ struct svm_range_list {
        <br>
              spinlock_t            deferred_list_lock;
        <br>
              atomic_t            evicted_ranges;
        <br>
              bool                drain_pagefaults;
        <br>
        +    atomic_t            draining_faults;
        <br>
              struct delayed_work        restore_work;
        <br>
              DECLARE_BITMAP(bitmap_supported, MAX_GPU_INSTANCE);
        <br>
              struct task_struct         *faulting_task;
        <br>
        diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
        b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
        <br>
        index 3eb0a9491755..d332462bf9d3 100644
        <br>
        --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
        <br>
        +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
        <br>
        @@ -1962,6 +1962,7 @@ void svm_range_drain_retry_fault(struct
        svm_range_list *svms)
        <br>
                p = container_of(svms, struct kfd_process, svms);
        <br>
          +    atomic_set(&svms->draining_faults, 1);
        <br>
              for_each_set_bit(i, svms->bitmap_supported,
        p->n_pdds) {
        <br>
                  pdd = p->pdds[i];
        <br>
                  if (!pdd)
        <br>
        @@ -1975,6 +1976,7 @@ void svm_range_drain_retry_fault(struct
        svm_range_list *svms)
        <br>
                  flush_work(&adev->irq.ih1_work);
        <br>
                  pr_debug("drain retry fault gpu %d svms 0x%p done\n",
        i, svms);
        <br>
              }
        <br>
        +    atomic_set(&svms->draining_faults, 0);
        <br>
          }
        <br>
            static void svm_range_deferred_list_work(struct work_struct
        *work)
        <br>
        @@ -2002,6 +2004,7 @@ static void
        svm_range_deferred_list_work(struct work_struct *work)
        <br>
               * mmap write lock to serialize with munmap notifiers.
        <br>
               */
        <br>
              if (unlikely(READ_ONCE(svms->drain_pagefaults))) {
        <br>
        +        atomic_set(&svms->draining_faults, 1);
        <br>
                  WRITE_ONCE(svms->drain_pagefaults, false);
        <br>
                  mmap_write_unlock(mm);
        <br>
                  svm_range_drain_retry_fault(svms);
        <br>
        @@ -2049,12 +2052,6 @@ svm_range_add_list_work(struct
        svm_range_list *svms, struct svm_range *prange,
        <br>
                      struct mm_struct *mm, enum svm_work_list_ops op)
        <br>
          {
        <br>
              spin_lock(&svms->deferred_list_lock);
        <br>
        -    /* Make sure pending page faults are drained in the
        deferred worker
        <br>
        -     * before the range is freed to avoid straggler interrupts
        on
        <br>
        -     * unmapped memory causing "phantom faults".
        <br>
        -     */
        <br>
        -    if (op == SVM_OP_UNMAP_RANGE)
        <br>
        -        svms->drain_pagefaults = true;
        <br>
              /* if prange is on the deferred list */
        <br>
              if (!list_empty(&prange->deferred_list)) {
        <br>
                  pr_debug("update exist prange 0x%p work op %d\n",
        prange, op);
        <br>
        @@ -2133,6 +2130,13 @@ svm_range_unmap_from_cpu(struct mm_struct
        *mm, struct svm_range *prange,
        <br>
              pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx] [0x%lx
        0x%lx]\n", svms,
        <br>
                   prange, prange->start, prange->last, start,
        last);
        <br>
          +    /* Make sure pending page faults are drained in the
        deferred worker
        <br>
        +     * before the range is freed to avoid straggler interrupts
        on
        <br>
        +     * unmapped memory causing "phantom faults".
        <br>
        +     */
        <br>
        +    pr_debug("set range drain_pagefaults true\n");
        <br>
        +    WRITE_ONCE(svms->drain_pagefaults, true);
        <br>
        +
        <br>
              unmap_parent = start <= prange->start &&
        last >= prange->last;
        <br>
                list_for_each_entry(pchild, &prange->child_list,
        child_list) {
        <br>
        @@ -2595,6 +2599,13 @@ svm_range_restore_pages(struct
        amdgpu_device *adev, unsigned int pasid,
        <br>
              mm = p->mm;
        <br>
              mmap_write_lock(mm);
        <br>
          +    if (!!atomic_read(&svms->draining_faults) ||
        <br>
        +        READ_ONCE(svms->drain_pagefaults)) {
        <br>
        +        pr_debug("draining retry fault, drop fault 0x%llx\n",
        addr);
        <br>
        +        mmap_write_downgrade(mm);
        <br>
        +        goto out_unlock_mm;
        <br>
        +    }
        <br>
        +
        <br>
              vma = find_vma(p->mm, addr << PAGE_SHIFT);
        <br>
              if (!vma || (addr << PAGE_SHIFT) <
        vma->vm_start) {
        <br>
                  pr_debug("VMA not found for address 0x%llx\n", addr);
        <br>
        @@ -2732,6 +2743,7 @@ int svm_range_list_init(struct kfd_process
        *p)
        <br>
              mutex_init(&svms->lock);
        <br>
              INIT_LIST_HEAD(&svms->list);
        <br>
              atomic_set(&svms->evicted_ranges, 0);
        <br>
        +    atomic_set(&svms->draining_faults, 0);
        <br>
              INIT_DELAYED_WORK(&svms->restore_work,
        svm_range_restore_work);
        <br>
              INIT_WORK(&svms->deferred_list_work,
        svm_range_deferred_list_work);
        <br>
              INIT_LIST_HEAD(&svms->deferred_range_list);
        <br>
      </blockquote>
    </blockquote>
  </body>
</html>