[PATCH 2/3] drm/nouveau: move io_reserve_lru handling into the driver v4

Dave Airlie airlied at gmail.com
Wed Aug 26 01:29:16 UTC 2020


On Sat, 22 Aug 2020 at 02:01, Christian König
<ckoenig.leichtzumerken at gmail.com> wrote:
>
> While working on TTM cleanups I've found that the io_reserve_lru used by
> Nouveau is actually not working at all.
>
> In general we should remove driver specific handling from the memory
> management, so this patch moves the io_reserve_lru handling into Nouveau
> instead.
>
> v2: don't call ttm_bo_unmap_virtual in nouveau_ttm_io_mem_reserve
> v3: rebased and use both base and offset in the check
> v4: fix small typos and test the patch
>
> Signed-off-by: Christian König <christian.koenig at amd.com>
> Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> ---
>  drivers/gpu/drm/nouveau/nouveau_bo.c  | 111 ++++++++++++++++++++------
>  drivers/gpu/drm/nouveau/nouveau_bo.h  |   3 +
>  drivers/gpu/drm/nouveau/nouveau_drv.h |   2 +
>  drivers/gpu/drm/nouveau/nouveau_ttm.c |  44 +++++++++-
>  4 files changed, 135 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
> index 5392e5fea5d4..ee0e135ddcbb 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_bo.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
> @@ -137,6 +137,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
>         struct nouveau_bo *nvbo = nouveau_bo(bo);
>
>         WARN_ON(nvbo->pin_refcnt > 0);
> +       nouveau_bo_del_io_reserve_lru(bo);
>         nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
>
>         /*
> @@ -304,6 +305,7 @@ nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 flags,
>
>         nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
>         nouveau_bo_placement_set(nvbo, flags, 0);
> +       INIT_LIST_HEAD(&nvbo->io_reserve_lru);
>
>         ret = ttm_bo_init(nvbo->bo.bdev, &nvbo->bo, size, type,
>                           &nvbo->placement, align >> PAGE_SHIFT, false,
> @@ -574,6 +576,26 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
>                                         PAGE_SIZE, DMA_FROM_DEVICE);
>  }
>
> +void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo)
> +{
> +       struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
> +       struct nouveau_bo *nvbo = nouveau_bo(bo);
> +
> +       mutex_lock(&drm->ttm.io_reserve_mutex);
> +       list_move_tail(&nvbo->io_reserve_lru, &drm->ttm.io_reserve_lru);
> +       mutex_unlock(&drm->ttm.io_reserve_mutex);
> +}
> +
> +void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo)
> +{
> +       struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
> +       struct nouveau_bo *nvbo = nouveau_bo(bo);
> +
> +       mutex_lock(&drm->ttm.io_reserve_mutex);
> +       list_del_init(&nvbo->io_reserve_lru);
> +       mutex_unlock(&drm->ttm.io_reserve_mutex);
> +}
> +
>  int
>  nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
>                     bool no_wait_gpu)
> @@ -888,6 +910,8 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
>         if (bo->destroy != nouveau_bo_del_ttm)
>                 return;
>
> +       nouveau_bo_del_io_reserve_lru(bo);
> +
>         if (mem && new_reg->mem_type != TTM_PL_SYSTEM &&
>             mem->mem.page == nvbo->page) {
>                 list_for_each_entry(vma, &nvbo->vma_list, head) {
> @@ -1018,23 +1042,54 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
>                                           filp->private_data);
>  }
>
> +static void
> +nouveau_ttm_io_mem_free_locked(struct nouveau_drm *drm,
> +                              struct ttm_resource *reg)
> +{
> +       struct nouveau_mem *mem = nouveau_mem(reg);
> +
> +       if (!reg->bus.base && !reg->bus.offset)
> +               return; /* already freed */
> +
> +       if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
> +               switch (reg->mem_type) {
> +               case TTM_PL_TT:
> +                       if (mem->kind)
> +                               nvif_object_unmap_handle(&mem->mem.object);
> +                       break;
> +               case TTM_PL_VRAM:
> +                       nvif_object_unmap_handle(&mem->mem.object);
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +       reg->bus.base = 0;
> +       reg->bus.offset = 0;
> +}
> +
>  static int
>  nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
>  {
>         struct nouveau_drm *drm = nouveau_bdev(bdev);
>         struct nvkm_device *device = nvxx_device(&drm->client.device);
>         struct nouveau_mem *mem = nouveau_mem(reg);
> +       int ret;
> +
> +       if (reg->bus.base || reg->bus.offset)
> +               return 0; /* already mapped */
>
>         reg->bus.addr = NULL;
> -       reg->bus.offset = 0;
>         reg->bus.size = reg->num_pages << PAGE_SHIFT;
> -       reg->bus.base = 0;
>         reg->bus.is_iomem = false;
>
> +       mutex_lock(&drm->ttm.io_reserve_mutex);
> +retry:
>         switch (reg->mem_type) {
>         case TTM_PL_SYSTEM:
>                 /* System memory */
> -               return 0;
> +               ret = 0;
> +               goto out;
>         case TTM_PL_TT:
>  #if IS_ENABLED(CONFIG_AGP)
>                 if (drm->agp.bridge) {
> @@ -1043,9 +1098,12 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
>                         reg->bus.is_iomem = !drm->agp.cma;
>                 }
>  #endif
> -               if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 || !mem->kind)
> +               if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 ||
> +                   !mem->kind) {
>                         /* untiled */
> +                       ret = 0;
>                         break;
> +               }
>                 fallthrough;    /* tiled memory */
>         case TTM_PL_VRAM:
>                 reg->bus.offset = reg->start << PAGE_SHIFT;
> @@ -1058,7 +1116,6 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
>                         } args;
>                         u64 handle, length;
>                         u32 argc = 0;
> -                       int ret;
>
>                         switch (mem->mem.object.oclass) {
>                         case NVIF_CLASS_MEM_NV50:
> @@ -1084,39 +1141,47 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
>                                                      &handle, &length);
>                         if (ret != 1) {
>                                 if (WARN_ON(ret == 0))
> -                                       return -EINVAL;
> -                               return ret;
> +                                       ret = -EINVAL;
> +                               goto out;
>                         }
>
>                         reg->bus.base = 0;
>                         reg->bus.offset = handle;
> +                       ret = 0;
>                 }
>                 break;
>         default:
> -               return -EINVAL;
> +               ret = -EINVAL;
>         }
> -       return 0;
> +
> +out:
> +       if (ret == -ENOSPC) {
> +               struct nouveau_bo *nvbo;
> +
> +               nvbo = list_first_entry_or_null(&drm->ttm.io_reserve_lru,
> +                                               typeof(*nvbo),
> +                                               io_reserve_lru);
> +               if (nvbo) {
> +                       list_del_init(&nvbo->io_reserve_lru);
> +                       drm_vma_node_unmap(&nvbo->bo.base.vma_node,
> +                                          bdev->dev_mapping);
> +                       nouveau_ttm_io_mem_free_locked(drm, &nvbo->bo.mem);
> +                       goto retry;
> +               }
> +
> +       }
> +       mutex_unlock(&drm->ttm.io_reserve_mutex);
> +       return ret;
>  }
>
>  static void
>  nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg)
>  {
>         struct nouveau_drm *drm = nouveau_bdev(bdev);
> -       struct nouveau_mem *mem = nouveau_mem(reg);
>
> -       if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
> -               switch (reg->mem_type) {
> -               case TTM_PL_TT:
> -                       if (mem->kind)
> -                               nvif_object_unmap_handle(&mem->mem.object);
> -                       break;
> -               case TTM_PL_VRAM:
> -                       nvif_object_unmap_handle(&mem->mem.object);
> -                       break;
> -               default:
> -                       break;
> -               }
> -       }
> +       mutex_lock(&drm->ttm.io_reserve_mutex);
> +       nouveau_ttm_io_mem_free_locked(drm, reg);
> +       mutex_unlock(&drm->ttm.io_reserve_mutex);
>  }
>
>  static int
> diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
> index aecb7481df0d..ae90aca33fef 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_bo.h
> +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
> @@ -18,6 +18,7 @@ struct nouveau_bo {
>         bool force_coherent;
>         struct ttm_bo_kmap_obj kmap;
>         struct list_head head;
> +       struct list_head io_reserve_lru;
>
>         /* protected by ttm_bo_reserve() */
>         struct drm_file *reserved_by;
> @@ -96,6 +97,8 @@ int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
>                          bool no_wait_gpu);
>  void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
>  void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
> +void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo);
> +void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo);
>
>  /* TODO: submit equivalent to TTM generic API upstream? */
>  static inline void __iomem *
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
> index f63ac72aa556..26a2c1090045 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
> +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
> @@ -164,6 +164,8 @@ struct nouveau_drm {
>                 int type_vram;
>                 int type_host[2];
>                 int type_ncoh[2];
> +               struct mutex io_reserve_mutex;
> +               struct list_head io_reserve_lru;
>         } ttm;
>
>         /* GEM interface support */
> diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
> index 53c6f8827322..a62f37b1131c 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
> @@ -123,13 +123,51 @@ const struct ttm_resource_manager_func nv04_gart_manager = {
>         .free = nouveau_manager_del,
>  };
>
> +static vm_fault_t nouveau_ttm_fault(struct vm_fault *vmf)
> +{
> +       struct vm_area_struct *vma = vmf->vma;
> +       struct ttm_buffer_object *bo = vma->vm_private_data;
> +       pgprot_t prot;
> +       vm_fault_t ret;
> +
> +       ret = ttm_bo_vm_reserve(bo, vmf);
> +       if (ret)
> +               return ret;
> +
> +       nouveau_bo_del_io_reserve_lru(bo);
> +
> +       prot = vm_get_page_prot(vma->vm_flags);
> +       ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT, 1);
> +       if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
> +               return ret;
> +
> +       nouveau_bo_add_io_reserve_lru(bo);
> +
> +       dma_resv_unlock(bo->base.resv);
> +
> +       return ret;
> +}
> +
> +static struct vm_operations_struct nouveau_ttm_vm_ops = {

should this be const?

Dave.


More information about the dri-devel mailing list