/** * radeon_driver_open_kms - drm callback for open * * @dev: drm dev pointer * @file_priv: drm file * * On device open, init vm on cayman+ (all asics). * Returns 0 on success, error on failure. */ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; int r; file_priv->driver_priv = NULL; r = pm_runtime_get_sync(dev->dev); if (r < 0) return r; /* new gpu have virtual address space support */ if (rdev->family >= CHIP_CAYMAN) { struct radeon_fpriv *fpriv; struct radeon_vm *vm; int r; fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); if (unlikely(!fpriv)) { return -ENOMEM; } if (rdev->accel_working) { vm = &fpriv->vm; r = radeon_vm_init(rdev, vm); if (r) { kfree(fpriv); return r; } r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (r) { radeon_vm_fini(rdev, vm); kfree(fpriv); return r; } /* map the ib pool buffer read only into * virtual address space */ vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); if (r) { radeon_vm_fini(rdev, vm); kfree(fpriv); return r; } } file_priv->driver_priv = fpriv; } pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return 0; }
/** * radeon_driver_open_kms - drm callback for open * * @dev: drm dev pointer * @file_priv: drm file * * On device open, init vm on cayman+ (all asics). * Returns 0 on success, error on failure. */ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; file_priv->driver_priv = NULL; /* new gpu have virtual address space support */ if (rdev->family >= CHIP_CAYMAN) { struct radeon_fpriv *fpriv; struct radeon_bo_va *bo_va; int r; fpriv = kmalloc(sizeof(*fpriv), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); if (unlikely(!fpriv)) { return -ENOMEM; } radeon_vm_init(rdev, &fpriv->vm); /* map the ib pool buffer read only into * virtual address space */ bo_va = radeon_vm_bo_add(rdev, &fpriv->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); if (r) { radeon_vm_fini(rdev, &fpriv->vm); drm_free(fpriv, DRM_MEM_DRIVER); return r; } file_priv->driver_priv = fpriv; } return 0; }
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; }