Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Christian König <christian.koenig@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Christian König and committed by
Alex Deucher
1ed3d256 aebc5e6f

+57 -6
+2 -2
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 1204 1204 * MMU Notifier 1205 1205 */ 1206 1206 #if defined(CONFIG_MMU_NOTIFIER) 1207 + void amdgpu_mn_lock(struct amdgpu_mn *mn); 1208 + void amdgpu_mn_unlock(struct amdgpu_mn *mn); 1207 1209 struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev); 1208 1210 int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr); 1209 1211 void amdgpu_mn_unregister(struct amdgpu_bo *bo); 1210 - void amdgpu_mn_lock(struct amdgpu_mn *mn); 1211 - void amdgpu_mn_unlock(struct amdgpu_mn *mn); 1212 1212 #else 1213 1213 static inline void amdgpu_mn_lock(struct amdgpu_mn *mn) {} 1214 1214 static inline void amdgpu_mn_unlock(struct amdgpu_mn *mn) {}
+55 -4
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
··· 52 52 /* objects protected by lock */ 53 53 struct rw_semaphore lock; 54 54 struct rb_root objects; 55 + struct mutex read_lock; 56 + atomic_t recursion; 55 57 }; 56 58 57 59 struct amdgpu_mn_node { ··· 128 126 } 129 127 130 128 /** 129 + * amdgpu_mn_read_lock - take the rmn read lock 130 + * 131 + * @rmn: our notifier 132 + * 133 + * Take the rmn read side lock. 134 + */ 135 + static void amdgpu_mn_read_lock(struct amdgpu_mn *rmn) 136 + { 137 + mutex_lock(&rmn->read_lock); 138 + if (atomic_inc_return(&rmn->recursion) == 1) 139 + down_read_non_owner(&rmn->lock); 140 + mutex_unlock(&rmn->read_lock); 141 + } 142 + 143 + /** 144 + * amdgpu_mn_read_unlock - drop the rmn read lock 145 + * 146 + * @rmn: our notifier 147 + * 148 + * Drop the rmn read side lock. 149 + */ 150 + static void amdgpu_mn_read_unlock(struct amdgpu_mn *rmn) 151 + { 152 + if (atomic_dec_return(&rmn->recursion) == 0) 153 + up_read_non_owner(&rmn->lock); 154 + } 155 + 156 + /** 131 157 * amdgpu_mn_invalidate_node - unmap all BOs of a node 132 158 * 133 159 * @node: the node with the BOs to unmap ··· 201 171 struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); 202 172 struct interval_tree_node *it; 203 173 204 - down_read(&rmn->lock); 174 + amdgpu_mn_read_lock(rmn); 205 175 206 176 it = interval_tree_iter_first(&rmn->objects, address, address); 207 177 if (it) { ··· 211 181 amdgpu_mn_invalidate_node(node, address, address); 212 182 } 213 183 214 - up_read(&rmn->lock); 184 + amdgpu_mn_read_unlock(rmn); 215 185 } 216 186 217 187 /** ··· 236 206 /* notification is exclusive, but interval is inclusive */ 237 207 end -= 1; 238 208 239 - down_read(&rmn->lock); 209 + amdgpu_mn_read_lock(rmn); 240 210 241 211 it = interval_tree_iter_first(&rmn->objects, start, end); 242 212 while (it) { ··· 247 217 248 218 amdgpu_mn_invalidate_node(node, start, end); 249 219 } 220 + } 250 221 251 - up_read(&rmn->lock); 222 + /** 223 + * amdgpu_mn_invalidate_range_end - callback to notify about mm change 224 + * 225 + * @mn: our notifier 226 + * @mn: the mm this callback is about 227 + * @start: start of updated range 228 + * @end: end of updated range 229 + * 230 + * Release the lock again to allow new command submissions. 231 + */ 232 + static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn, 233 + struct mm_struct *mm, 234 + unsigned long start, 235 + unsigned long end) 236 + { 237 + struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); 238 + 239 + amdgpu_mn_read_unlock(rmn); 252 240 } 253 241 254 242 static const struct mmu_notifier_ops amdgpu_mn_ops = { 255 243 .release = amdgpu_mn_release, 256 244 .invalidate_page = amdgpu_mn_invalidate_page, 257 245 .invalidate_range_start = amdgpu_mn_invalidate_range_start, 246 + .invalidate_range_end = amdgpu_mn_invalidate_range_end, 258 247 }; 259 248 260 249 /** ··· 310 261 rmn->mn.ops = &amdgpu_mn_ops; 311 262 init_rwsem(&rmn->lock); 312 263 rmn->objects = RB_ROOT; 264 + mutex_init(&rmn->read_lock); 265 + atomic_set(&rmn->recursion, 0); 313 266 314 267 r = __mmu_notifier_register(&rmn->mn, mm); 315 268 if (r)