[PATCH 8/8] drm/radeon: rework the VM code a bit more

Jerome Glisse j.glisse at gmail.com
Tue Sep 11 09:11:31 PDT 2012


On Tue, Sep 11, 2012 at 10:10 AM, Christian König
<deathsimple at vodafone.de> wrote:
> Roughly based on how nouveau is handling it. Instead of
> adding the bo_va when the address is set add the bo_va
> when the handle is opened, but set the address to zero
> until userspace tells us where to place it.
>
> This fixes another bunch of problems with glamor.

What exactly are the fix ? I don't see why this change is needed. It
make things more complicated in my view.

>
> Signed-off-by: Christian König <deathsimple at vodafone.de>
> ---
>  drivers/gpu/drm/radeon/radeon.h      |   30 ++++---
>  drivers/gpu/drm/radeon/radeon_gart.c |  147 ++++++++++++++++++++++------------
>  drivers/gpu/drm/radeon/radeon_gem.c  |   47 +++++++++--
>  3 files changed, 153 insertions(+), 71 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 8cca1d2..4d67f0f 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -292,17 +292,20 @@ struct radeon_mman {
>
>  /* bo virtual address in a specific vm */
>  struct radeon_bo_va {
> -       /* bo list is protected by bo being reserved */
> +       /* protected by bo being reserved */
>         struct list_head                bo_list;
> -       /* vm list is protected by vm mutex */
> -       struct list_head                vm_list;
> -       /* constant after initialization */
> -       struct radeon_vm                *vm;
> -       struct radeon_bo                *bo;
>         uint64_t                        soffset;
>         uint64_t                        eoffset;
>         uint32_t                        flags;
>         bool                            valid;
> +       unsigned                        ref_count;

unsigned refcount is a recipe for failure, if somehow you over unref
then you va will stay alive forever and this overunref will probably
go unnoticed.

> +
> +       /* protected by vm mutex */
> +       struct list_head                vm_list;
> +
> +       /* constant after initialization */
> +       struct radeon_vm                *vm;
> +       struct radeon_bo                *bo;
>  };
>
>  struct radeon_bo {
> @@ -1848,14 +1851,15 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
>                              struct radeon_bo *bo);
>  struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
>                                        struct radeon_bo *bo);
> -int radeon_vm_bo_add(struct radeon_device *rdev,
> -                    struct radeon_vm *vm,
> -                    struct radeon_bo *bo,
> -                    uint64_t offset,
> -                    uint32_t flags);
> +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
> +                                     struct radeon_vm *vm,
> +                                     struct radeon_bo *bo);
> +int radeon_vm_bo_set_addr(struct radeon_device *rdev,
> +                         struct radeon_bo_va *bo_va,
> +                         uint64_t offset,
> +                         uint32_t flags);
>  int radeon_vm_bo_rmv(struct radeon_device *rdev,
> -                    struct radeon_vm *vm,
> -                    struct radeon_bo *bo);
> +                    struct radeon_bo_va *bo_va);
>
>  /* audio */
>  void r600_audio_update_hdmi(struct work_struct *work);
> diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
> index 2c59491..2f28ff3 100644
> --- a/drivers/gpu/drm/radeon/radeon_gart.c
> +++ b/drivers/gpu/drm/radeon/radeon_gart.c
> @@ -693,51 +693,83 @@ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
>   * @rdev: radeon_device pointer
>   * @vm: requested vm
>   * @bo: radeon buffer object
> - * @offset: requested offset of the buffer in the VM address space
> - * @flags: attributes of pages (read/write/valid/etc.)
>   *
>   * Add @bo into the requested vm (cayman+).
> - * Add @bo to the list of bos associated with the vm and validate
> - * the offset requested within the vm address space.
> - * Returns 0 for success, error for failure.
> + * Add @bo to the list of bos associated with the vm
> + * Returns newly added bo_va or NULL for failure
>   *
>   * Object has to be reserved!
>   */
> -int radeon_vm_bo_add(struct radeon_device *rdev,
> -                    struct radeon_vm *vm,
> -                    struct radeon_bo *bo,
> -                    uint64_t offset,
> -                    uint32_t flags)
> +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
> +                                     struct radeon_vm *vm,
> +                                     struct radeon_bo *bo)
>  {
> -       struct radeon_bo_va *bo_va, *tmp;
> -       struct list_head *head;
> -       uint64_t size = radeon_bo_size(bo), last_offset = 0;
> -       unsigned last_pfn;
> +       struct radeon_bo_va *bo_va;
>
>         bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
>         if (bo_va == NULL) {
> -               return -ENOMEM;
> +               return NULL;
>         }
>         bo_va->vm = vm;
>         bo_va->bo = bo;
> -       bo_va->soffset = offset;
> -       bo_va->eoffset = offset + size;
> -       bo_va->flags = flags;
> +       bo_va->soffset = 0;
> +       bo_va->eoffset = 0;
> +       bo_va->flags = 0;
>         bo_va->valid = false;
> +       bo_va->ref_count = 1;
>         INIT_LIST_HEAD(&bo_va->bo_list);
>         INIT_LIST_HEAD(&bo_va->vm_list);
> -       /* make sure object fit at this offset */
> -       if (bo_va->soffset >= bo_va->eoffset) {
> -               kfree(bo_va);
> -               return -EINVAL;
> -       }
>
> -       last_pfn = bo_va->eoffset / RADEON_GPU_PAGE_SIZE;
> -       if (last_pfn > rdev->vm_manager.max_pfn) {
> -               kfree(bo_va);
> -               dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
> -                       last_pfn, rdev->vm_manager.max_pfn);
> -               return -EINVAL;
> +       mutex_lock(&vm->mutex);
> +       list_add(&bo_va->vm_list, &vm->va);
> +       list_add_tail(&bo_va->bo_list, &bo->va);
> +       mutex_unlock(&vm->mutex);
> +
> +       return bo_va;
> +}
> +
> +/**
> + * radeon_vm_bo_set_addr - set bos virtual address inside a vm
> + *
> + * @rdev: radeon_device pointer
> + * @bo_va: bo_va to store the address
> + * @soffset: requested offset of the buffer in the VM address space
> + * @flags: attributes of pages (read/write/valid/etc.)
> + *
> + * Set offset of @bo_va (cayman+).
> + * Validate and set the offset requested within the vm address space.
> + * Returns 0 for success, error for failure.
> + *
> + * Object has to be reserved!
> + */
> +int radeon_vm_bo_set_addr(struct radeon_device *rdev,
> +                         struct radeon_bo_va *bo_va,
> +                         uint64_t soffset,
> +                         uint32_t flags)
> +{
> +       uint64_t size = radeon_bo_size(bo_va->bo);
> +       uint64_t eoffset, last_offset = 0;
> +       struct radeon_vm *vm = bo_va->vm;
> +       struct radeon_bo_va *tmp;
> +       struct list_head *head;
> +       unsigned last_pfn;
> +
> +       if (soffset) {
> +               /* make sure object fit at this offset */
> +               eoffset = soffset + size;
> +               if (soffset >= eoffset) {
> +                       return -EINVAL;
> +               }
> +
> +               last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
> +               if (last_pfn > rdev->vm_manager.max_pfn) {
> +                       dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
> +                               last_pfn, rdev->vm_manager.max_pfn);
> +                       return -EINVAL;
> +               }
> +
> +       } else {
> +               eoffset = last_pfn = 0;
>         }
>
>         mutex_lock(&vm->mutex);
> @@ -758,24 +790,33 @@ int radeon_vm_bo_add(struct radeon_device *rdev,
>         head = &vm->va;
>         last_offset = 0;
>         list_for_each_entry(tmp, &vm->va, vm_list) {
> -               if (bo_va->soffset >= last_offset && bo_va->eoffset <= tmp->soffset) {
> +               if (bo_va == tmp) {
> +                       /* skip over currently modified bo */
> +                       continue;
> +               }
> +
> +               if (soffset >= last_offset && eoffset <= tmp->soffset) {
>                         /* bo can be added before this one */
>                         break;
>                 }
> -               if (bo_va->eoffset > tmp->soffset && bo_va->soffset < tmp->eoffset) {
> +               if (eoffset > tmp->soffset && soffset < tmp->eoffset) {
>                         /* bo and tmp overlap, invalid offset */
>                         dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n",
> -                               bo, (unsigned)bo_va->soffset, tmp->bo,
> +                               bo_va->bo, (unsigned)bo_va->soffset, tmp->bo,
>                                 (unsigned)tmp->soffset, (unsigned)tmp->eoffset);
> -                       kfree(bo_va);
>                         mutex_unlock(&vm->mutex);
>                         return -EINVAL;
>                 }
>                 last_offset = tmp->eoffset;
>                 head = &tmp->vm_list;
>         }
> -       list_add(&bo_va->vm_list, head);
> -       list_add_tail(&bo_va->bo_list, &bo->va);
> +
> +       bo_va->soffset = soffset;
> +       bo_va->eoffset = eoffset;
> +       bo_va->flags = flags;
> +       bo_va->valid = false;
> +       list_move(&bo_va->vm_list, head);
> +
>         mutex_unlock(&vm->mutex);
>         return 0;
>  }
> @@ -855,6 +896,12 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
>                 return -EINVAL;
>         }
>
> +       if (!bo_va->soffset) {
> +               dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n",
> +                       bo, vm);
> +               return -EINVAL;
> +       }
> +
>         if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL))
>                 return 0;
>
> @@ -921,33 +968,26 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
>   * radeon_vm_bo_rmv - remove a bo to a specific vm
>   *
>   * @rdev: radeon_device pointer
> - * @vm: requested vm
> - * @bo: radeon buffer object
> + * @bo_va: requested bo_va
>   *
> - * Remove @bo from the requested vm (cayman+).
> - * Remove @bo from the list of bos associated with the vm and
> - * remove the ptes for @bo in the page table.
> + * Remove @bo_va->bo from the requested vm (cayman+).
> + * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and
> + * remove the ptes for @bo_va in the page table.
>   * Returns 0 for success.
>   *
>   * Object have to be reserved!
>   */
>  int radeon_vm_bo_rmv(struct radeon_device *rdev,
> -                    struct radeon_vm *vm,
> -                    struct radeon_bo *bo)
> +                    struct radeon_bo_va *bo_va)
>  {
> -       struct radeon_bo_va *bo_va;
>         int r;
>
> -       bo_va = radeon_vm_bo_find(vm, bo);
> -       if (bo_va == NULL)
> -               return 0;
> -
>         mutex_lock(&rdev->vm_manager.lock);
> -       mutex_lock(&vm->mutex);
> -       r = radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
> +       mutex_lock(&bo_va->vm->mutex);
> +       r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL);
>         mutex_unlock(&rdev->vm_manager.lock);
>         list_del(&bo_va->vm_list);
> -       mutex_unlock(&vm->mutex);
> +       mutex_unlock(&bo_va->vm->mutex);
>         list_del(&bo_va->bo_list);
>
>         kfree(bo_va);
> @@ -987,6 +1027,7 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
>   */
>  int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
>  {
> +       struct radeon_bo_va *bo_va;
>         int r;
>
>         vm->id = 0;
> @@ -1006,8 +1047,10 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
>         /* map the ib pool buffer at 0 in virtual address space, set
>          * read only
>          */
> -       r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, RADEON_VA_IB_OFFSET,
> -                            RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED);
> +       bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo);
> +       r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
> +                                 RADEON_VM_PAGE_READABLE |
> +                                 RADEON_VM_PAGE_SNOOPED);
>         return r;
>  }
>
> diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
> index cfad667..6579bef 100644
> --- a/drivers/gpu/drm/radeon/radeon_gem.c
> +++ b/drivers/gpu/drm/radeon/radeon_gem.c
> @@ -124,6 +124,30 @@ void radeon_gem_fini(struct radeon_device *rdev)
>   */
>  int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
>  {
> +       struct radeon_bo *rbo = gem_to_radeon_bo(obj);
> +       struct radeon_device *rdev = rbo->rdev;
> +       struct radeon_fpriv *fpriv = file_priv->driver_priv;
> +       struct radeon_vm *vm = &fpriv->vm;
> +       struct radeon_bo_va *bo_va;
> +       int r;
> +
> +       if (rdev->family < CHIP_CAYMAN) {
> +               return 0;
> +       }
> +
> +       r = radeon_bo_reserve(rbo, false);
> +       if (r) {
> +               return r;
> +       }
> +
> +       bo_va = radeon_vm_bo_find(vm, rbo);
> +       if (!bo_va) {
> +               bo_va = radeon_vm_bo_add(rdev, vm, rbo);
> +       } else {
> +               ++bo_va->ref_count;
> +       }
> +       radeon_bo_unreserve(rbo);
> +
>         return 0;
>  }
>
> @@ -134,6 +158,7 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
>         struct radeon_device *rdev = rbo->rdev;
>         struct radeon_fpriv *fpriv = file_priv->driver_priv;
>         struct radeon_vm *vm = &fpriv->vm;
> +       struct radeon_bo_va *bo_va;
>         int r;
>
>         if (rdev->family < CHIP_CAYMAN) {
> @@ -146,7 +171,12 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
>                         "we fail to reserve bo (%d)\n", r);
>                 return;
>         }
> -       radeon_vm_bo_rmv(rdev, vm, rbo);
> +       bo_va = radeon_vm_bo_find(vm, rbo);
> +       if (bo_va) {
> +               if (--bo_va->ref_count == 0) {
> +                       radeon_vm_bo_rmv(rdev, bo_va);
> +               }
> +       }
>         radeon_bo_unreserve(rbo);
>  }
>
> @@ -462,19 +492,24 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
>                 drm_gem_object_unreference_unlocked(gobj);
>                 return r;
>         }
> +       bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
> +       if (!bo_va) {
> +               args->operation = RADEON_VA_RESULT_ERROR;
> +               drm_gem_object_unreference_unlocked(gobj);
> +               return -ENOENT;
> +       }
> +
>         switch (args->operation) {
>         case RADEON_VA_MAP:
> -               bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
> -               if (bo_va) {
> +               if (bo_va->soffset) {
>                         args->operation = RADEON_VA_RESULT_VA_EXIST;
>                         args->offset = bo_va->soffset;
>                         goto out;
>                 }
> -               r = radeon_vm_bo_add(rdev, &fpriv->vm, rbo,
> -                                    args->offset, args->flags);
> +               r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
>                 break;
>         case RADEON_VA_UNMAP:
> -               r = radeon_vm_bo_rmv(rdev, &fpriv->vm, rbo);
> +               r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0);
>                 break;
>         default:
>                 break;
> --
> 1.7.9.5
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list