linux/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
<<
>>
Prefs
   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 <christian.koenig@amd.com>
  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 <drm/drm.h>
  49
  50#include "amdgpu.h"
  51#include "amdgpu_amdkfd.h"
  52
  53/**
  54 * amdgpu_mn_invalidate_gfx - callback to notify about mm change
  55 *
  56 * @mni: the range (mm) is about to update
  57 * @range: details on the invalidation
  58 * @cur_seq: Value to pass to mmu_interval_set_seq()
  59 *
  60 * Block for operations on BOs to finish and mark pages as accessed and
  61 * potentially dirty.
  62 */
  63static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
  64                                     const struct mmu_notifier_range *range,
  65                                     unsigned long cur_seq)
  66{
  67        struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
  68        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
  69        long r;
  70
  71        if (!mmu_notifier_range_blockable(range))
  72                return false;
  73
  74        mutex_lock(&adev->notifier_lock);
  75
  76        mmu_interval_set_seq(mni, cur_seq);
  77
  78        r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
  79                                  MAX_SCHEDULE_TIMEOUT);
  80        mutex_unlock(&adev->notifier_lock);
  81        if (r <= 0)
  82                DRM_ERROR("(%ld) failed to wait for user bo\n", r);
  83        return true;
  84}
  85
  86static const struct mmu_interval_notifier_ops amdgpu_mn_gfx_ops = {
  87        .invalidate = amdgpu_mn_invalidate_gfx,
  88};
  89
  90/**
  91 * amdgpu_mn_invalidate_hsa - callback to notify about mm change
  92 *
  93 * @mni: the range (mm) is about to update
  94 * @range: details on the invalidation
  95 * @cur_seq: Value to pass to mmu_interval_set_seq()
  96 *
  97 * We temporarily evict the BO attached to this range. This necessitates
  98 * evicting all user-mode queues of the process.
  99 */
 100static bool amdgpu_mn_invalidate_hsa(struct mmu_interval_notifier *mni,
 101                                     const struct mmu_notifier_range *range,
 102                                     unsigned long cur_seq)
 103{
 104        struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);
 105        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
 106
 107        if (!mmu_notifier_range_blockable(range))
 108                return false;
 109
 110        mutex_lock(&adev->notifier_lock);
 111
 112        mmu_interval_set_seq(mni, cur_seq);
 113
 114        amdgpu_amdkfd_evict_userptr(bo->kfd_bo, bo->notifier.mm);
 115        mutex_unlock(&adev->notifier_lock);
 116
 117        return true;
 118}
 119
 120static const struct mmu_interval_notifier_ops amdgpu_mn_hsa_ops = {
 121        .invalidate = amdgpu_mn_invalidate_hsa,
 122};
 123
 124/**
 125 * amdgpu_mn_register - register a BO for notifier updates
 126 *
 127 * @bo: amdgpu buffer object
 128 * @addr: userptr addr we should monitor
 129 *
 130 * Registers a mmu_notifier for the given BO at the specified address.
 131 * Returns 0 on success, -ERRNO if anything goes wrong.
 132 */
 133int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
 134{
 135        if (bo->kfd_bo)
 136                return mmu_interval_notifier_insert(&bo->notifier, current->mm,
 137                                                    addr, amdgpu_bo_size(bo),
 138                                                    &amdgpu_mn_hsa_ops);
 139        return mmu_interval_notifier_insert(&bo->notifier, current->mm, addr,
 140                                            amdgpu_bo_size(bo),
 141                                            &amdgpu_mn_gfx_ops);
 142}
 143
 144/**
 145 * amdgpu_mn_unregister - unregister a BO for notifier updates
 146 *
 147 * @bo: amdgpu buffer object
 148 *
 149 * Remove any registration of mmu notifier updates from the buffer object.
 150 */
 151void amdgpu_mn_unregister(struct amdgpu_bo *bo)
 152{
 153        if (!bo->notifier.mm)
 154                return;
 155        mmu_interval_notifier_remove(&bo->notifier);
 156        bo->notifier.mm = NULL;
 157}
 158
 159int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
 160                               struct mm_struct *mm, struct page **pages,
 161                               uint64_t start, uint64_t npages,
 162                               struct hmm_range **phmm_range, bool readonly,
 163                               bool mmap_locked, void *owner)
 164{
 165        struct hmm_range *hmm_range;
 166        unsigned long timeout;
 167        unsigned long i;
 168        unsigned long *pfns;
 169        int r = 0;
 170
 171        hmm_range = kzalloc(sizeof(*hmm_range), GFP_KERNEL);
 172        if (unlikely(!hmm_range))
 173                return -ENOMEM;
 174
 175        pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
 176        if (unlikely(!pfns)) {
 177                r = -ENOMEM;
 178                goto out_free_range;
 179        }
 180
 181        hmm_range->notifier = notifier;
 182        hmm_range->default_flags = HMM_PFN_REQ_FAULT;
 183        if (!readonly)
 184                hmm_range->default_flags |= HMM_PFN_REQ_WRITE;
 185        hmm_range->hmm_pfns = pfns;
 186        hmm_range->start = start;
 187        hmm_range->end = start + npages * PAGE_SIZE;
 188        hmm_range->dev_private_owner = owner;
 189
 190        /* Assuming 512MB takes maxmium 1 second to fault page address */
 191        timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT;
 192        timeout = jiffies + msecs_to_jiffies(timeout);
 193
 194retry:
 195        hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
 196
 197        if (likely(!mmap_locked))
 198                mmap_read_lock(mm);
 199
 200        r = hmm_range_fault(hmm_range);
 201
 202        if (likely(!mmap_locked))
 203                mmap_read_unlock(mm);
 204        if (unlikely(r)) {
 205                /*
 206                 * FIXME: This timeout should encompass the retry from
 207                 * mmu_interval_read_retry() as well.
 208                 */
 209                if (r == -EBUSY && !time_after(jiffies, timeout))
 210                        goto retry;
 211                goto out_free_pfns;
 212        }
 213
 214        /*
 215         * Due to default_flags, all pages are HMM_PFN_VALID or
 216         * hmm_range_fault() fails. FIXME: The pages cannot be touched outside
 217         * the notifier_lock, and mmu_interval_read_retry() must be done first.
 218         */
 219        for (i = 0; pages && i < npages; i++)
 220                pages[i] = hmm_pfn_to_page(pfns[i]);
 221
 222        *phmm_range = hmm_range;
 223
 224        return 0;
 225
 226out_free_pfns:
 227        kvfree(pfns);
 228out_free_range:
 229        kfree(hmm_range);
 230
 231        return r;
 232}
 233
 234int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range)
 235{
 236        int r;
 237
 238        r = mmu_interval_read_retry(hmm_range->notifier,
 239                                    hmm_range->notifier_seq);
 240        kvfree(hmm_range->hmm_pfns);
 241        kfree(hmm_range);
 242
 243        return r;
 244}
 245