diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 111 |
1 files changed, 88 insertions, 23 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index bd67f4cb8e6c..83e344fbb50a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | |||
| @@ -36,12 +36,14 @@ | |||
| 36 | #include <drm/drm.h> | 36 | #include <drm/drm.h> |
| 37 | 37 | ||
| 38 | #include "amdgpu.h" | 38 | #include "amdgpu.h" |
| 39 | #include "amdgpu_amdkfd.h" | ||
| 39 | 40 | ||
| 40 | struct amdgpu_mn { | 41 | struct amdgpu_mn { |
| 41 | /* constant after initialisation */ | 42 | /* constant after initialisation */ |
| 42 | struct amdgpu_device *adev; | 43 | struct amdgpu_device *adev; |
| 43 | struct mm_struct *mm; | 44 | struct mm_struct *mm; |
| 44 | struct mmu_notifier mn; | 45 | struct mmu_notifier mn; |
| 46 | enum amdgpu_mn_type type; | ||
| 45 | 47 | ||
| 46 | /* only used on destruction */ | 48 | /* only used on destruction */ |
| 47 | struct work_struct work; | 49 | struct work_struct work; |
| @@ -185,7 +187,7 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, | |||
| 185 | } | 187 | } |
| 186 | 188 | ||
| 187 | /** | 189 | /** |
| 188 | * amdgpu_mn_invalidate_range_start - callback to notify about mm change | 190 | * amdgpu_mn_invalidate_range_start_gfx - callback to notify about mm change |
| 189 | * | 191 | * |
| 190 | * @mn: our notifier | 192 | * @mn: our notifier |
| 191 | * @mn: the mm this callback is about | 193 | * @mn: the mm this callback is about |
| @@ -195,10 +197,10 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, | |||
| 195 | * We block for all BOs between start and end to be idle and | 197 | * We block for all BOs between start and end to be idle and |
| 196 | * unmap them by move them into system domain again. | 198 | * unmap them by move them into system domain again. |
| 197 | */ | 199 | */ |
| 198 | static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn, | 200 | static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, |
| 199 | struct mm_struct *mm, | 201 | struct mm_struct *mm, |
| 200 | unsigned long start, | 202 | unsigned long start, |
| 201 | unsigned long end) | 203 | unsigned long end) |
| 202 | { | 204 | { |
| 203 | struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); | 205 | struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); |
| 204 | struct interval_tree_node *it; | 206 | struct interval_tree_node *it; |
| @@ -220,6 +222,49 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn, | |||
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | /** | 224 | /** |
| 225 | * amdgpu_mn_invalidate_range_start_hsa - callback to notify about mm change | ||
| 226 | * | ||
| 227 | * @mn: our notifier | ||
| 228 | * @mn: the mm this callback is about | ||
| 229 | * @start: start of updated range | ||
| 230 | * @end: end of updated range | ||
| 231 | * | ||
| 232 | * We temporarily evict all BOs between start and end. This | ||
| 233 | * necessitates evicting all user-mode queues of the process. The BOs | ||
| 234 | * are restorted in amdgpu_mn_invalidate_range_end_hsa. | ||
| 235 | */ | ||
| 236 | static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, | ||
| 237 | struct mm_struct *mm, | ||
| 238 | unsigned long start, | ||
| 239 | unsigned long end) | ||
| 240 | { | ||
| 241 | struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); | ||
| 242 | struct interval_tree_node *it; | ||
| 243 | |||
| 244 | /* notification is exclusive, but interval is inclusive */ | ||
| 245 | end -= 1; | ||
| 246 | |||
| 247 | amdgpu_mn_read_lock(rmn); | ||
| 248 | |||
| 249 | it = interval_tree_iter_first(&rmn->objects, start, end); | ||
| 250 | while (it) { | ||
| 251 | struct amdgpu_mn_node *node; | ||
| 252 | struct amdgpu_bo *bo; | ||
| 253 | |||
| 254 | node = container_of(it, struct amdgpu_mn_node, it); | ||
| 255 | it = interval_tree_iter_next(it, start, end); | ||
| 256 | |||
| 257 | list_for_each_entry(bo, &node->bos, mn_list) { | ||
| 258 | struct kgd_mem *mem = bo->kfd_bo; | ||
| 259 | |||
| 260 | if (amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, | ||
| 261 | start, end)) | ||
| 262 | amdgpu_amdkfd_evict_userptr(mem, mm); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /** | ||
| 223 | * amdgpu_mn_invalidate_range_end - callback to notify about mm change | 268 | * amdgpu_mn_invalidate_range_end - callback to notify about mm change |
| 224 | * | 269 | * |
| 225 | * @mn: our notifier | 270 | * @mn: our notifier |
| @@ -239,23 +284,39 @@ static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn, | |||
| 239 | amdgpu_mn_read_unlock(rmn); | 284 | amdgpu_mn_read_unlock(rmn); |
| 240 | } | 285 | } |
| 241 | 286 | ||
| 242 | static const struct mmu_notifier_ops amdgpu_mn_ops = { | 287 | static const struct mmu_notifier_ops amdgpu_mn_ops[] = { |
| 243 | .release = amdgpu_mn_release, | 288 | [AMDGPU_MN_TYPE_GFX] = { |
| 244 | .invalidate_range_start = amdgpu_mn_invalidate_range_start, | 289 | .release = amdgpu_mn_release, |
| 245 | .invalidate_range_end = amdgpu_mn_invalidate_range_end, | 290 | .invalidate_range_start = amdgpu_mn_invalidate_range_start_gfx, |
| 291 | .invalidate_range_end = amdgpu_mn_invalidate_range_end, | ||
| 292 | }, | ||
| 293 | [AMDGPU_MN_TYPE_HSA] = { | ||
| 294 | .release = amdgpu_mn_release, | ||
| 295 | .invalidate_range_start = amdgpu_mn_invalidate_range_start_hsa, | ||
| 296 | .invalidate_range_end = amdgpu_mn_invalidate_range_end, | ||
| 297 | }, | ||
| 246 | }; | 298 | }; |
| 247 | 299 | ||
| 300 | /* Low bits of any reasonable mm pointer will be unused due to struct | ||
| 301 | * alignment. Use these bits to make a unique key from the mm pointer | ||
| 302 | * and notifier type. | ||
| 303 | */ | ||
| 304 | #define AMDGPU_MN_KEY(mm, type) ((unsigned long)(mm) + (type)) | ||
| 305 | |||
| 248 | /** | 306 | /** |
| 249 | * amdgpu_mn_get - create notifier context | 307 | * amdgpu_mn_get - create notifier context |
| 250 | * | 308 | * |
| 251 | * @adev: amdgpu device pointer | 309 | * @adev: amdgpu device pointer |
| 310 | * @type: type of MMU notifier context | ||
| 252 | * | 311 | * |
| 253 | * Creates a notifier context for current->mm. | 312 | * Creates a notifier context for current->mm. |
| 254 | */ | 313 | */ |
| 255 | struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev) | 314 | struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev, |
| 315 | enum amdgpu_mn_type type) | ||
| 256 | { | 316 | { |
| 257 | struct mm_struct *mm = current->mm; | 317 | struct mm_struct *mm = current->mm; |
| 258 | struct amdgpu_mn *rmn; | 318 | struct amdgpu_mn *rmn; |
| 319 | unsigned long key = AMDGPU_MN_KEY(mm, type); | ||
| 259 | int r; | 320 | int r; |
| 260 | 321 | ||
| 261 | mutex_lock(&adev->mn_lock); | 322 | mutex_lock(&adev->mn_lock); |
| @@ -264,8 +325,8 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev) | |||
| 264 | return ERR_PTR(-EINTR); | 325 | return ERR_PTR(-EINTR); |
| 265 | } | 326 | } |
| 266 | 327 | ||
| 267 | hash_for_each_possible(adev->mn_hash, rmn, node, (unsigned long)mm) | 328 | hash_for_each_possible(adev->mn_hash, rmn, node, key) |
| 268 | if (rmn->mm == mm) | 329 | if (AMDGPU_MN_KEY(rmn->mm, rmn->type) == key) |
| 269 | goto release_locks; | 330 | goto release_locks; |
| 270 | 331 | ||
| 271 | rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); | 332 | rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); |
| @@ -276,8 +337,9 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev) | |||
| 276 | 337 | ||
| 277 | rmn->adev = adev; | 338 | rmn->adev = adev; |
| 278 | rmn->mm = mm; | 339 | rmn->mm = mm; |
| 279 | rmn->mn.ops = &amdgpu_mn_ops; | ||
| 280 | init_rwsem(&rmn->lock); | 340 | init_rwsem(&rmn->lock); |
| 341 | rmn->type = type; | ||
| 342 | rmn->mn.ops = &amdgpu_mn_ops[type]; | ||
| 281 | rmn->objects = RB_ROOT_CACHED; | 343 | rmn->objects = RB_ROOT_CACHED; |
| 282 | mutex_init(&rmn->read_lock); | 344 | mutex_init(&rmn->read_lock); |
| 283 | atomic_set(&rmn->recursion, 0); | 345 | atomic_set(&rmn->recursion, 0); |
| @@ -286,7 +348,7 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev) | |||
| 286 | if (r) | 348 | if (r) |
| 287 | goto free_rmn; | 349 | goto free_rmn; |
| 288 | 350 | ||
| 289 | hash_add(adev->mn_hash, &rmn->node, (unsigned long)mm); | 351 | hash_add(adev->mn_hash, &rmn->node, AMDGPU_MN_KEY(mm, type)); |
| 290 | 352 | ||
| 291 | release_locks: | 353 | release_locks: |
| 292 | up_write(&mm->mmap_sem); | 354 | up_write(&mm->mmap_sem); |
| @@ -315,15 +377,21 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) | |||
| 315 | { | 377 | { |
| 316 | unsigned long end = addr + amdgpu_bo_size(bo) - 1; | 378 | unsigned long end = addr + amdgpu_bo_size(bo) - 1; |
| 317 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 379 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
| 380 | enum amdgpu_mn_type type = | ||
| 381 | bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX; | ||
| 318 | struct amdgpu_mn *rmn; | 382 | struct amdgpu_mn *rmn; |
| 319 | struct amdgpu_mn_node *node = NULL; | 383 | struct amdgpu_mn_node *node = NULL, *new_node; |
| 320 | struct list_head bos; | 384 | struct list_head bos; |
| 321 | struct interval_tree_node *it; | 385 | struct interval_tree_node *it; |
| 322 | 386 | ||
| 323 | rmn = amdgpu_mn_get(adev); | 387 | rmn = amdgpu_mn_get(adev, type); |
| 324 | if (IS_ERR(rmn)) | 388 | if (IS_ERR(rmn)) |
| 325 | return PTR_ERR(rmn); | 389 | return PTR_ERR(rmn); |
| 326 | 390 | ||
| 391 | new_node = kmalloc(sizeof(*new_node), GFP_KERNEL); | ||
| 392 | if (!new_node) | ||
| 393 | return -ENOMEM; | ||
| 394 | |||
| 327 | INIT_LIST_HEAD(&bos); | 395 | INIT_LIST_HEAD(&bos); |
| 328 | 396 | ||
| 329 | down_write(&rmn->lock); | 397 | down_write(&rmn->lock); |
| @@ -337,13 +405,10 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) | |||
| 337 | list_splice(&node->bos, &bos); | 405 | list_splice(&node->bos, &bos); |
| 338 | } | 406 | } |
| 339 | 407 | ||
| 340 | if (!node) { | 408 | if (!node) |
| 341 | node = kmalloc(sizeof(struct amdgpu_mn_node), GFP_KERNEL); | 409 | node = new_node; |
| 342 | if (!node) { | 410 | else |
| 343 | up_write(&rmn->lock); | 411 | kfree(new_node); |
| 344 | return -ENOMEM; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | 412 | ||
| 348 | bo->mn = rmn; | 413 | bo->mn = rmn; |
| 349 | 414 | ||
