/** * radeon_driver_postclose_kms - drm callback for post close * * @dev: drm dev pointer * @file_priv: drm file * * On device post close, tear down vm on cayman+ (all asics). */ void radeon_driver_postclose_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; /* new gpu have virtual address space support */ if (rdev->family >= CHIP_CAYMAN && file_priv->driver_priv) { struct radeon_fpriv *fpriv = file_priv->driver_priv; struct radeon_bo_va *bo_va; int r; r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (!r) { bo_va = radeon_vm_bo_find(&fpriv->vm, rdev->ring_tmp_bo.bo); if (bo_va) radeon_vm_bo_rmv(rdev, bo_va); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); } radeon_vm_fini(rdev, &fpriv->vm); kfree(fpriv); file_priv->driver_priv = NULL; } }
void radeon_gem_object_close(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; } r = radeon_bo_reserve(rbo, true); if (r) { dev_err(rdev->dev, "leaking bo va because " "we fail to reserve bo (%d)\n", r); return; } 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); }
/* * Call from drm_gem_handle_create which appear in both new and open ioctl * case. */ 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; }
static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p, struct radeon_vm *vm) { struct radeon_device *rdev = p->rdev; struct radeon_bo_va *bo_va; int i, r; r = radeon_vm_update_page_directory(rdev, vm); if (r) return r; r = radeon_vm_clear_freed(rdev, vm); if (r) return r; if (vm->ib_bo_va == NULL) { DRM_ERROR("Tmp BO not in VM!\n"); return -EINVAL; } r = radeon_vm_bo_update(rdev, vm->ib_bo_va, &rdev->ring_tmp_bo.bo->tbo.mem); if (r) return r; for (i = 0; i < p->nrelocs; i++) { struct radeon_bo *bo; /* ignore duplicates */ if (p->relocs_ptr[i] != &p->relocs[i]) continue; bo = p->relocs[i].robj; bo_va = radeon_vm_bo_find(vm, bo); if (bo_va == NULL) { dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm); return -EINVAL; } r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem); if (r) return r; } return radeon_vm_clear_invalids(rdev, vm); }
int radeon_gem_va_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct drm_radeon_gem_va *args = data; struct drm_gem_object *gobj; struct radeon_device *rdev = dev->dev_private; struct radeon_fpriv *fpriv = filp->driver_priv; struct radeon_bo *rbo; struct radeon_bo_va *bo_va; u32 invalid_flags; int r = 0; if (!rdev->vm_manager.enabled) { args->operation = RADEON_VA_RESULT_ERROR; return -ENOTTY; } /* !! DONT REMOVE !! * We don't support vm_id yet, to be sure we don't have have broken * userspace, reject anyone trying to use non 0 value thus moving * forward we can use those fields without breaking existant userspace */ if (args->vm_id) { args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } if (args->offset < RADEON_VA_RESERVED_SIZE) { dev_err(dev->device, "offset 0x%lX is in reserved area 0x%X\n", (unsigned long)args->offset, RADEON_VA_RESERVED_SIZE); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } /* don't remove, we need to enforce userspace to set the snooped flag * otherwise we will endup with broken userspace and we won't be able * to enable this feature without adding new interface */ invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM; if ((args->flags & invalid_flags)) { dev_err(dev->device, "invalid flags 0x%08X vs 0x%08X\n", args->flags, invalid_flags); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } if (!(args->flags & RADEON_VM_PAGE_SNOOPED)) { dev_err(dev->device, "only supported snooped mapping for now\n"); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } switch (args->operation) { case RADEON_VA_MAP: case RADEON_VA_UNMAP: break; default: dev_err(dev->device, "unsupported operation %d\n", args->operation); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } gobj = drm_gem_object_lookup(dev, filp, args->handle); if (gobj == NULL) { args->operation = RADEON_VA_RESULT_ERROR; return -ENOENT; } rbo = gem_to_radeon_bo(gobj); r = radeon_bo_reserve(rbo, false); if (r) { args->operation = RADEON_VA_RESULT_ERROR; 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: if (bo_va->soffset) { args->operation = RADEON_VA_RESULT_VA_EXIST; args->offset = bo_va->soffset; goto out; } r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); break; case RADEON_VA_UNMAP: r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0); break; default: break; } args->operation = RADEON_VA_RESULT_OK; if (r) { args->operation = RADEON_VA_RESULT_ERROR; } out: radeon_bo_unreserve(rbo); drm_gem_object_unreference_unlocked(gobj); return r; }