Commit 1ed3d256 authored by Christian König's avatar Christian König Committed by Alex Deucher

drm/amdgpu: keep the MMU lock until the update ends v4

This is quite controversial because it adds another lock which is held during
page table updates, but I don't see much other option.

v2: allow multiple updates to be in flight at the same time
v3: simplify the patch, take the read side only once
v4: correctly fix rebase conflict
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent aebc5e6f
...@@ -1204,11 +1204,11 @@ void amdgpu_test_moves(struct amdgpu_device *adev); ...@@ -1204,11 +1204,11 @@ void amdgpu_test_moves(struct amdgpu_device *adev);
* MMU Notifier * MMU Notifier
*/ */
#if defined(CONFIG_MMU_NOTIFIER) #if defined(CONFIG_MMU_NOTIFIER)
void amdgpu_mn_lock(struct amdgpu_mn *mn);
void amdgpu_mn_unlock(struct amdgpu_mn *mn);
struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev); struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev);
int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr); int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr);
void amdgpu_mn_unregister(struct amdgpu_bo *bo); void amdgpu_mn_unregister(struct amdgpu_bo *bo);
void amdgpu_mn_lock(struct amdgpu_mn *mn);
void amdgpu_mn_unlock(struct amdgpu_mn *mn);
#else #else
static inline void amdgpu_mn_lock(struct amdgpu_mn *mn) {} static inline void amdgpu_mn_lock(struct amdgpu_mn *mn) {}
static inline void amdgpu_mn_unlock(struct amdgpu_mn *mn) {} static inline void amdgpu_mn_unlock(struct amdgpu_mn *mn) {}
......
...@@ -52,6 +52,8 @@ struct amdgpu_mn { ...@@ -52,6 +52,8 @@ struct amdgpu_mn {
/* objects protected by lock */ /* objects protected by lock */
struct rw_semaphore lock; struct rw_semaphore lock;
struct rb_root objects; struct rb_root objects;
struct mutex read_lock;
atomic_t recursion;
}; };
struct amdgpu_mn_node { struct amdgpu_mn_node {
...@@ -125,6 +127,34 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn) ...@@ -125,6 +127,34 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn)
up_write(&mn->lock); up_write(&mn->lock);
} }
/**
* amdgpu_mn_read_lock - take the rmn read lock
*
* @rmn: our notifier
*
* Take the rmn read side lock.
*/
static void amdgpu_mn_read_lock(struct amdgpu_mn *rmn)
{
mutex_lock(&rmn->read_lock);
if (atomic_inc_return(&rmn->recursion) == 1)
down_read_non_owner(&rmn->lock);
mutex_unlock(&rmn->read_lock);
}
/**
* amdgpu_mn_read_unlock - drop the rmn read lock
*
* @rmn: our notifier
*
* Drop the rmn read side lock.
*/
static void amdgpu_mn_read_unlock(struct amdgpu_mn *rmn)
{
if (atomic_dec_return(&rmn->recursion) == 0)
up_read_non_owner(&rmn->lock);
}
/** /**
* amdgpu_mn_invalidate_node - unmap all BOs of a node * amdgpu_mn_invalidate_node - unmap all BOs of a node
* *
...@@ -171,7 +201,7 @@ static void amdgpu_mn_invalidate_page(struct mmu_notifier *mn, ...@@ -171,7 +201,7 @@ static void amdgpu_mn_invalidate_page(struct mmu_notifier *mn,
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
struct interval_tree_node *it; struct interval_tree_node *it;
down_read(&rmn->lock); amdgpu_mn_read_lock(rmn);
it = interval_tree_iter_first(&rmn->objects, address, address); it = interval_tree_iter_first(&rmn->objects, address, address);
if (it) { if (it) {
...@@ -181,7 +211,7 @@ static void amdgpu_mn_invalidate_page(struct mmu_notifier *mn, ...@@ -181,7 +211,7 @@ static void amdgpu_mn_invalidate_page(struct mmu_notifier *mn,
amdgpu_mn_invalidate_node(node, address, address); amdgpu_mn_invalidate_node(node, address, address);
} }
up_read(&rmn->lock); amdgpu_mn_read_unlock(rmn);
} }
/** /**
...@@ -206,7 +236,7 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn, ...@@ -206,7 +236,7 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn,
/* notification is exclusive, but interval is inclusive */ /* notification is exclusive, but interval is inclusive */
end -= 1; end -= 1;
down_read(&rmn->lock); amdgpu_mn_read_lock(rmn);
it = interval_tree_iter_first(&rmn->objects, start, end); it = interval_tree_iter_first(&rmn->objects, start, end);
while (it) { while (it) {
...@@ -217,14 +247,33 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn, ...@@ -217,14 +247,33 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn,
amdgpu_mn_invalidate_node(node, start, end); amdgpu_mn_invalidate_node(node, start, end);
} }
}
/**
* amdgpu_mn_invalidate_range_end - callback to notify about mm change
*
* @mn: our notifier
* @mn: the mm this callback is about
* @start: start of updated range
* @end: end of updated range
*
* Release the lock again to allow new command submissions.
*/
static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long start,
unsigned long end)
{
struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
up_read(&rmn->lock); amdgpu_mn_read_unlock(rmn);
} }
static const struct mmu_notifier_ops amdgpu_mn_ops = { static const struct mmu_notifier_ops amdgpu_mn_ops = {
.release = amdgpu_mn_release, .release = amdgpu_mn_release,
.invalidate_page = amdgpu_mn_invalidate_page, .invalidate_page = amdgpu_mn_invalidate_page,
.invalidate_range_start = amdgpu_mn_invalidate_range_start, .invalidate_range_start = amdgpu_mn_invalidate_range_start,
.invalidate_range_end = amdgpu_mn_invalidate_range_end,
}; };
/** /**
...@@ -261,6 +310,8 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev) ...@@ -261,6 +310,8 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev)
rmn->mn.ops = &amdgpu_mn_ops; rmn->mn.ops = &amdgpu_mn_ops;
init_rwsem(&rmn->lock); init_rwsem(&rmn->lock);
rmn->objects = RB_ROOT; rmn->objects = RB_ROOT;
mutex_init(&rmn->read_lock);
atomic_set(&rmn->recursion, 0);
r = __mmu_notifier_register(&rmn->mn, mm); r = __mmu_notifier_register(&rmn->mn, mm);
if (r) if (r)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment