]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
Merge branch 'drm-next' into drm-next-5.3
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_mn.c
1 /*
2  * Copyright 2014 Advanced Micro Devices, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19  * USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * The above copyright notice and this permission notice (including the
22  * next paragraph) shall be included in all copies or substantial portions
23  * of the Software.
24  *
25  */
26 /*
27  * Authors:
28  *    Christian König <[email protected]>
29  */
30
31 /**
32  * DOC: MMU Notifier
33  *
34  * For coherent userptr handling registers an MMU notifier to inform the driver
35  * about updates on the page tables of a process.
36  *
37  * When somebody tries to invalidate the page tables we block the update until
38  * all operations on the pages in question are completed, then those pages are
39  * marked as accessed and also dirty if it wasn't a read only access.
40  *
41  * New command submissions using the userptrs in question are delayed until all
42  * page table invalidation are completed and we once more see a coherent process
43  * address space.
44  */
45
46 #include <linux/firmware.h>
47 #include <linux/module.h>
48 #include <linux/hmm.h>
49 #include <linux/interval_tree.h>
50
51 #include <drm/drm.h>
52
53 #include "amdgpu.h"
54 #include "amdgpu_amdkfd.h"
55
56 /**
57  * struct amdgpu_mn
58  *
59  * @adev: amdgpu device pointer
60  * @mm: process address space
61  * @type: type of MMU notifier
62  * @work: destruction work item
63  * @node: hash table node to find structure by adev and mn
64  * @lock: rw semaphore protecting the notifier nodes
65  * @objects: interval tree containing amdgpu_mn_nodes
66  * @mirror: HMM mirror function support
67  *
68  * Data for each amdgpu device and process address space.
69  */
70 struct amdgpu_mn {
71         /* constant after initialisation */
72         struct amdgpu_device    *adev;
73         struct mm_struct        *mm;
74         enum amdgpu_mn_type     type;
75
76         /* only used on destruction */
77         struct work_struct      work;
78
79         /* protected by adev->mn_lock */
80         struct hlist_node       node;
81
82         /* objects protected by lock */
83         struct rw_semaphore     lock;
84         struct rb_root_cached   objects;
85
86         /* HMM mirror */
87         struct hmm_mirror       mirror;
88 };
89
90 /**
91  * struct amdgpu_mn_node
92  *
93  * @it: interval node defining start-last of the affected address range
94  * @bos: list of all BOs in the affected address range
95  *
96  * Manages all BOs which are affected of a certain range of address space.
97  */
98 struct amdgpu_mn_node {
99         struct interval_tree_node       it;
100         struct list_head                bos;
101 };
102
103 /**
104  * amdgpu_mn_destroy - destroy the HMM mirror
105  *
106  * @work: previously sheduled work item
107  *
108  * Lazy destroys the notifier from a work item
109  */
110 static void amdgpu_mn_destroy(struct work_struct *work)
111 {
112         struct amdgpu_mn *amn = container_of(work, struct amdgpu_mn, work);
113         struct amdgpu_device *adev = amn->adev;
114         struct amdgpu_mn_node *node, *next_node;
115         struct amdgpu_bo *bo, *next_bo;
116
117         mutex_lock(&adev->mn_lock);
118         down_write(&amn->lock);
119         hash_del(&amn->node);
120         rbtree_postorder_for_each_entry_safe(node, next_node,
121                                              &amn->objects.rb_root, it.rb) {
122                 list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
123                         bo->mn = NULL;
124                         list_del_init(&bo->mn_list);
125                 }
126                 kfree(node);
127         }
128         up_write(&amn->lock);
129         mutex_unlock(&adev->mn_lock);
130
131         hmm_mirror_unregister(&amn->mirror);
132         kfree(amn);
133 }
134
135 /**
136  * amdgpu_hmm_mirror_release - callback to notify about mm destruction
137  *
138  * @mirror: the HMM mirror (mm) this callback is about
139  *
140  * Shedule a work item to lazy destroy HMM mirror.
141  */
142 static void amdgpu_hmm_mirror_release(struct hmm_mirror *mirror)
143 {
144         struct amdgpu_mn *amn = container_of(mirror, struct amdgpu_mn, mirror);
145
146         INIT_WORK(&amn->work, amdgpu_mn_destroy);
147         schedule_work(&amn->work);
148 }
149
150 /**
151  * amdgpu_mn_lock - take the write side lock for this notifier
152  *
153  * @mn: our notifier
154  */
155 void amdgpu_mn_lock(struct amdgpu_mn *mn)
156 {
157         if (mn)
158                 down_write(&mn->lock);
159 }
160
161 /**
162  * amdgpu_mn_unlock - drop the write side lock for this notifier
163  *
164  * @mn: our notifier
165  */
166 void amdgpu_mn_unlock(struct amdgpu_mn *mn)
167 {
168         if (mn)
169                 up_write(&mn->lock);
170 }
171
172 /**
173  * amdgpu_mn_read_lock - take the read side lock for this notifier
174  *
175  * @amn: our notifier
176  */
177 static int amdgpu_mn_read_lock(struct amdgpu_mn *amn, bool blockable)
178 {
179         if (blockable)
180                 down_read(&amn->lock);
181         else if (!down_read_trylock(&amn->lock))
182                 return -EAGAIN;
183
184         return 0;
185 }
186
187 /**
188  * amdgpu_mn_read_unlock - drop the read side lock for this notifier
189  *
190  * @amn: our notifier
191  */
192 static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn)
193 {
194         up_read(&amn->lock);
195 }
196
197 /**
198  * amdgpu_mn_invalidate_node - unmap all BOs of a node
199  *
200  * @node: the node with the BOs to unmap
201  * @start: start of address range affected
202  * @end: end of address range affected
203  *
204  * Block for operations on BOs to finish and mark pages as accessed and
205  * potentially dirty.
206  */
207 static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
208                                       unsigned long start,
209                                       unsigned long end)
210 {
211         struct amdgpu_bo *bo;
212         long r;
213
214         list_for_each_entry(bo, &node->bos, mn_list) {
215
216                 if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start, end))
217                         continue;
218
219                 r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
220                         true, false, MAX_SCHEDULE_TIMEOUT);
221                 if (r <= 0)
222                         DRM_ERROR("(%ld) failed to wait for user bo\n", r);
223         }
224 }
225
226 /**
227  * amdgpu_mn_sync_pagetables_gfx - callback to notify about mm change
228  *
229  * @mirror: the hmm_mirror (mm) is about to update
230  * @update: the update start, end address
231  *
232  * Block for operations on BOs to finish and mark pages as accessed and
233  * potentially dirty.
234  */
235 static int amdgpu_mn_sync_pagetables_gfx(struct hmm_mirror *mirror,
236                         const struct hmm_update *update)
237 {
238         struct amdgpu_mn *amn = container_of(mirror, struct amdgpu_mn, mirror);
239         unsigned long start = update->start;
240         unsigned long end = update->end;
241         bool blockable = update->blockable;
242         struct interval_tree_node *it;
243
244         /* notification is exclusive, but interval is inclusive */
245         end -= 1;
246
247         /* TODO we should be able to split locking for interval tree and
248          * amdgpu_mn_invalidate_node
249          */
250         if (amdgpu_mn_read_lock(amn, blockable))
251                 return -EAGAIN;
252
253         it = interval_tree_iter_first(&amn->objects, start, end);
254         while (it) {
255                 struct amdgpu_mn_node *node;
256
257                 if (!blockable) {
258                         amdgpu_mn_read_unlock(amn);
259                         return -EAGAIN;
260                 }
261
262                 node = container_of(it, struct amdgpu_mn_node, it);
263                 it = interval_tree_iter_next(it, start, end);
264
265                 amdgpu_mn_invalidate_node(node, start, end);
266         }
267
268         amdgpu_mn_read_unlock(amn);
269
270         return 0;
271 }
272
273 /**
274  * amdgpu_mn_sync_pagetables_hsa - callback to notify about mm change
275  *
276  * @mirror: the hmm_mirror (mm) is about to update
277  * @update: the update start, end address
278  *
279  * We temporarily evict all BOs between start and end. This
280  * necessitates evicting all user-mode queues of the process. The BOs
281  * are restorted in amdgpu_mn_invalidate_range_end_hsa.
282  */
283 static int amdgpu_mn_sync_pagetables_hsa(struct hmm_mirror *mirror,
284                         const struct hmm_update *update)
285 {
286         struct amdgpu_mn *amn = container_of(mirror, struct amdgpu_mn, mirror);
287         unsigned long start = update->start;
288         unsigned long end = update->end;
289         bool blockable = update->blockable;
290         struct interval_tree_node *it;
291
292         /* notification is exclusive, but interval is inclusive */
293         end -= 1;
294
295         if (amdgpu_mn_read_lock(amn, blockable))
296                 return -EAGAIN;
297
298         it = interval_tree_iter_first(&amn->objects, start, end);
299         while (it) {
300                 struct amdgpu_mn_node *node;
301                 struct amdgpu_bo *bo;
302
303                 if (!blockable) {
304                         amdgpu_mn_read_unlock(amn);
305                         return -EAGAIN;
306                 }
307
308                 node = container_of(it, struct amdgpu_mn_node, it);
309                 it = interval_tree_iter_next(it, start, end);
310
311                 list_for_each_entry(bo, &node->bos, mn_list) {
312                         struct kgd_mem *mem = bo->kfd_bo;
313
314                         if (amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm,
315                                                          start, end))
316                                 amdgpu_amdkfd_evict_userptr(mem, amn->mm);
317                 }
318         }
319
320         amdgpu_mn_read_unlock(amn);
321
322         return 0;
323 }
324
325 /* Low bits of any reasonable mm pointer will be unused due to struct
326  * alignment. Use these bits to make a unique key from the mm pointer
327  * and notifier type.
328  */
329 #define AMDGPU_MN_KEY(mm, type) ((unsigned long)(mm) + (type))
330
331 static struct hmm_mirror_ops amdgpu_hmm_mirror_ops[] = {
332         [AMDGPU_MN_TYPE_GFX] = {
333                 .sync_cpu_device_pagetables = amdgpu_mn_sync_pagetables_gfx,
334                 .release = amdgpu_hmm_mirror_release
335         },
336         [AMDGPU_MN_TYPE_HSA] = {
337                 .sync_cpu_device_pagetables = amdgpu_mn_sync_pagetables_hsa,
338                 .release = amdgpu_hmm_mirror_release
339         },
340 };
341
342 /**
343  * amdgpu_mn_get - create HMM mirror context
344  *
345  * @adev: amdgpu device pointer
346  * @type: type of MMU notifier context
347  *
348  * Creates a HMM mirror context for current->mm.
349  */
350 struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev,
351                                 enum amdgpu_mn_type type)
352 {
353         struct mm_struct *mm = current->mm;
354         struct amdgpu_mn *amn;
355         unsigned long key = AMDGPU_MN_KEY(mm, type);
356         int r;
357
358         mutex_lock(&adev->mn_lock);
359         if (down_write_killable(&mm->mmap_sem)) {
360                 mutex_unlock(&adev->mn_lock);
361                 return ERR_PTR(-EINTR);
362         }
363
364         hash_for_each_possible(adev->mn_hash, amn, node, key)
365                 if (AMDGPU_MN_KEY(amn->mm, amn->type) == key)
366                         goto release_locks;
367
368         amn = kzalloc(sizeof(*amn), GFP_KERNEL);
369         if (!amn) {
370                 amn = ERR_PTR(-ENOMEM);
371                 goto release_locks;
372         }
373
374         amn->adev = adev;
375         amn->mm = mm;
376         init_rwsem(&amn->lock);
377         amn->type = type;
378         amn->objects = RB_ROOT_CACHED;
379
380         amn->mirror.ops = &amdgpu_hmm_mirror_ops[type];
381         r = hmm_mirror_register(&amn->mirror, mm);
382         if (r)
383                 goto free_amn;
384
385         hash_add(adev->mn_hash, &amn->node, AMDGPU_MN_KEY(mm, type));
386
387 release_locks:
388         up_write(&mm->mmap_sem);
389         mutex_unlock(&adev->mn_lock);
390
391         return amn;
392
393 free_amn:
394         up_write(&mm->mmap_sem);
395         mutex_unlock(&adev->mn_lock);
396         kfree(amn);
397
398         return ERR_PTR(r);
399 }
400
401 /**
402  * amdgpu_mn_register - register a BO for notifier updates
403  *
404  * @bo: amdgpu buffer object
405  * @addr: userptr addr we should monitor
406  *
407  * Registers an HMM mirror for the given BO at the specified address.
408  * Returns 0 on success, -ERRNO if anything goes wrong.
409  */
410 int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
411 {
412         unsigned long end = addr + amdgpu_bo_size(bo) - 1;
413         struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
414         enum amdgpu_mn_type type =
415                 bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX;
416         struct amdgpu_mn *amn;
417         struct amdgpu_mn_node *node = NULL, *new_node;
418         struct list_head bos;
419         struct interval_tree_node *it;
420
421         amn = amdgpu_mn_get(adev, type);
422         if (IS_ERR(amn))
423                 return PTR_ERR(amn);
424
425         new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
426         if (!new_node)
427                 return -ENOMEM;
428
429         INIT_LIST_HEAD(&bos);
430
431         down_write(&amn->lock);
432
433         while ((it = interval_tree_iter_first(&amn->objects, addr, end))) {
434                 kfree(node);
435                 node = container_of(it, struct amdgpu_mn_node, it);
436                 interval_tree_remove(&node->it, &amn->objects);
437                 addr = min(it->start, addr);
438                 end = max(it->last, end);
439                 list_splice(&node->bos, &bos);
440         }
441
442         if (!node)
443                 node = new_node;
444         else
445                 kfree(new_node);
446
447         bo->mn = amn;
448
449         node->it.start = addr;
450         node->it.last = end;
451         INIT_LIST_HEAD(&node->bos);
452         list_splice(&bos, &node->bos);
453         list_add(&bo->mn_list, &node->bos);
454
455         interval_tree_insert(&node->it, &amn->objects);
456
457         up_write(&amn->lock);
458
459         return 0;
460 }
461
462 /**
463  * amdgpu_mn_unregister - unregister a BO for HMM mirror updates
464  *
465  * @bo: amdgpu buffer object
466  *
467  * Remove any registration of HMM mirror updates from the buffer object.
468  */
469 void amdgpu_mn_unregister(struct amdgpu_bo *bo)
470 {
471         struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
472         struct amdgpu_mn *amn;
473         struct list_head *head;
474
475         mutex_lock(&adev->mn_lock);
476
477         amn = bo->mn;
478         if (amn == NULL) {
479                 mutex_unlock(&adev->mn_lock);
480                 return;
481         }
482
483         down_write(&amn->lock);
484
485         /* save the next list entry for later */
486         head = bo->mn_list.next;
487
488         bo->mn = NULL;
489         list_del_init(&bo->mn_list);
490
491         if (list_empty(head)) {
492                 struct amdgpu_mn_node *node;
493
494                 node = container_of(head, struct amdgpu_mn_node, bos);
495                 interval_tree_remove(&node->it, &amn->objects);
496                 kfree(node);
497         }
498
499         up_write(&amn->lock);
500         mutex_unlock(&adev->mn_lock);
501 }
502
503 /* flags used by HMM internal, not related to CPU/GPU PTE flags */
504 static const uint64_t hmm_range_flags[HMM_PFN_FLAG_MAX] = {
505                 (1 << 0), /* HMM_PFN_VALID */
506                 (1 << 1), /* HMM_PFN_WRITE */
507                 0 /* HMM_PFN_DEVICE_PRIVATE */
508 };
509
510 static const uint64_t hmm_range_values[HMM_PFN_VALUE_MAX] = {
511                 0xfffffffffffffffeUL, /* HMM_PFN_ERROR */
512                 0, /* HMM_PFN_NONE */
513                 0xfffffffffffffffcUL /* HMM_PFN_SPECIAL */
514 };
515
516 void amdgpu_hmm_init_range(struct hmm_range *range)
517 {
518         if (range) {
519                 range->flags = hmm_range_flags;
520                 range->values = hmm_range_values;
521                 range->pfn_shift = PAGE_SHIFT;
522                 INIT_LIST_HEAD(&range->list);
523         }
524 }
This page took 0.066275 seconds and 4 git commands to generate.