<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>