drm/msm: Add opt-in for VM_BIND
Add a SET_PARAM for userspace to request to manage to the VM itself, instead of getting a kernel managed VM. In order to transition to a userspace managed VM, this param must be set before any mappings are created. Signed-off-by: Rob Clark <robdclark@chromium.org> Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Patchwork: https://patchwork.freedesktop.org/patch/661494/
This commit is contained in:
@@ -2276,7 +2276,7 @@ a6xx_create_vm(struct msm_gpu *gpu, struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static struct drm_gpuvm *
|
||||
a6xx_create_private_vm(struct msm_gpu *gpu)
|
||||
a6xx_create_private_vm(struct msm_gpu *gpu, bool kernel_managed)
|
||||
{
|
||||
struct msm_mmu *mmu;
|
||||
|
||||
@@ -2286,7 +2286,7 @@ a6xx_create_private_vm(struct msm_gpu *gpu)
|
||||
return ERR_CAST(mmu);
|
||||
|
||||
return msm_gem_vm_create(gpu->dev, mmu, "gpu", ADRENO_VM_START,
|
||||
adreno_private_vm_size(gpu), true);
|
||||
adreno_private_vm_size(gpu), kernel_managed);
|
||||
}
|
||||
|
||||
static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
|
||||
|
||||
@@ -504,6 +504,21 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_context *ctx,
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return UERR(EPERM, drm, "invalid permissions");
|
||||
return msm_context_set_sysprof(ctx, gpu, value);
|
||||
case MSM_PARAM_EN_VM_BIND:
|
||||
/* We can only support VM_BIND with per-process pgtables: */
|
||||
if (ctx->vm == gpu->vm)
|
||||
return UERR(EINVAL, drm, "requires per-process pgtables");
|
||||
|
||||
/*
|
||||
* We can only swtich to VM_BIND mode if the VM has not yet
|
||||
* been created:
|
||||
*/
|
||||
if (ctx->vm)
|
||||
return UERR(EBUSY, drm, "VM already created");
|
||||
|
||||
ctx->userspace_managed_vm = value;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
|
||||
}
|
||||
|
||||
@@ -232,9 +232,21 @@ static void load_gpu(struct drm_device *dev)
|
||||
*/
|
||||
struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx)
|
||||
{
|
||||
static DEFINE_MUTEX(init_lock);
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
if (!ctx->vm)
|
||||
ctx->vm = msm_gpu_create_private_vm(priv->gpu, current);
|
||||
|
||||
/* Once ctx->vm is created it is valid for the lifetime of the context: */
|
||||
if (ctx->vm)
|
||||
return ctx->vm;
|
||||
|
||||
mutex_lock(&init_lock);
|
||||
if (!ctx->vm) {
|
||||
ctx->vm = msm_gpu_create_private_vm(
|
||||
priv->gpu, current, !ctx->userspace_managed_vm);
|
||||
|
||||
}
|
||||
mutex_unlock(&init_lock);
|
||||
|
||||
return ctx->vm;
|
||||
}
|
||||
|
||||
@@ -424,6 +436,9 @@ static int msm_ioctl_gem_info_iova(struct drm_device *dev,
|
||||
if (!priv->gpu)
|
||||
return -EINVAL;
|
||||
|
||||
if (msm_context_is_vmbind(ctx))
|
||||
return UERR(EINVAL, dev, "VM_BIND is enabled");
|
||||
|
||||
if (should_fail(&fail_gem_iova, obj->size))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -445,6 +460,9 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,
|
||||
if (!priv->gpu)
|
||||
return -EINVAL;
|
||||
|
||||
if (msm_context_is_vmbind(ctx))
|
||||
return UERR(EINVAL, dev, "VM_BIND is enabled");
|
||||
|
||||
/* Only supported if per-process address space is supported: */
|
||||
if (priv->gpu->vm == vm)
|
||||
return UERR(EOPNOTSUPP, dev, "requires per-process pgtables");
|
||||
|
||||
@@ -81,6 +81,14 @@ static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
|
||||
if (!ctx->vm)
|
||||
return;
|
||||
|
||||
/*
|
||||
* VM_BIND does not depend on implicit teardown of VMAs on handle
|
||||
* close, but instead on implicit teardown of the VM when the device
|
||||
* is closed (see msm_gem_vm_close())
|
||||
*/
|
||||
if (msm_context_is_vmbind(ctx))
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO we might need to kick this to a queue to avoid blocking
|
||||
* in CLOSE ioctl
|
||||
|
||||
@@ -829,7 +829,8 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu)
|
||||
|
||||
/* Return a new address space for a msm_drm_private instance */
|
||||
struct drm_gpuvm *
|
||||
msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task)
|
||||
msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task,
|
||||
bool kernel_managed)
|
||||
{
|
||||
struct drm_gpuvm *vm = NULL;
|
||||
|
||||
@@ -841,7 +842,7 @@ msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task)
|
||||
* the global one
|
||||
*/
|
||||
if (gpu->funcs->create_private_vm) {
|
||||
vm = gpu->funcs->create_private_vm(gpu);
|
||||
vm = gpu->funcs->create_private_vm(gpu, kernel_managed);
|
||||
if (!IS_ERR(vm))
|
||||
to_msm_vm(vm)->pid = get_pid(task_pid(task));
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ struct msm_gpu_funcs {
|
||||
void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp,
|
||||
bool suspended);
|
||||
struct drm_gpuvm *(*create_vm)(struct msm_gpu *gpu, struct platform_device *pdev);
|
||||
struct drm_gpuvm *(*create_private_vm)(struct msm_gpu *gpu);
|
||||
struct drm_gpuvm *(*create_private_vm)(struct msm_gpu *gpu, bool kernel_managed);
|
||||
uint32_t (*get_rptr)(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
|
||||
|
||||
/**
|
||||
@@ -364,6 +364,14 @@ struct msm_context {
|
||||
*/
|
||||
bool closed;
|
||||
|
||||
/**
|
||||
* @userspace_managed_vm:
|
||||
*
|
||||
* Has userspace opted-in to userspace managed VM (ie. VM_BIND) via
|
||||
* MSM_PARAM_EN_VM_BIND?
|
||||
*/
|
||||
bool userspace_managed_vm;
|
||||
|
||||
/**
|
||||
* @vm:
|
||||
*
|
||||
@@ -456,6 +464,22 @@ struct msm_context {
|
||||
|
||||
struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx);
|
||||
|
||||
/**
|
||||
* msm_context_is_vm_bind() - has userspace opted in to VM_BIND?
|
||||
*
|
||||
* @ctx: the drm_file context
|
||||
*
|
||||
* See MSM_PARAM_EN_VM_BIND. If userspace is managing the VM, it can
|
||||
* do sparse binding including having multiple, potentially partial,
|
||||
* mappings in the VM. Therefore certain legacy uabi (ie. GET_IOVA,
|
||||
* SET_IOVA) are rejected because they don't have a sensible meaning.
|
||||
*/
|
||||
static inline bool
|
||||
msm_context_is_vmbind(struct msm_context *ctx)
|
||||
{
|
||||
return ctx->userspace_managed_vm;
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_gpu_convert_priority - Map userspace priority to ring # and sched priority
|
||||
*
|
||||
@@ -683,7 +707,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
|
||||
const char *name, struct msm_gpu_config *config);
|
||||
|
||||
struct drm_gpuvm *
|
||||
msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task);
|
||||
msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task,
|
||||
bool kernel_managed);
|
||||
|
||||
void msm_gpu_cleanup(struct msm_gpu *gpu);
|
||||
|
||||
|
||||
@@ -93,6 +93,30 @@ struct drm_msm_timespec {
|
||||
#define MSM_PARAM_UCHE_TRAP_BASE 0x14 /* RO */
|
||||
/* PRR (Partially Resident Region) is required for sparse residency: */
|
||||
#define MSM_PARAM_HAS_PRR 0x15 /* RO */
|
||||
/* MSM_PARAM_EN_VM_BIND is set to 1 to enable VM_BIND ops.
|
||||
*
|
||||
* With VM_BIND enabled, userspace is required to allocate iova and use the
|
||||
* VM_BIND ops for map/unmap ioctls. MSM_INFO_SET_IOVA and MSM_INFO_GET_IOVA
|
||||
* will be rejected. (The latter does not have a sensible meaning when a BO
|
||||
* can have multiple and/or partial mappings.)
|
||||
*
|
||||
* With VM_BIND enabled, userspace does not include a submit_bo table in the
|
||||
* SUBMIT ioctl (this will be rejected), the resident set is determined by
|
||||
* the the VM_BIND ops.
|
||||
*
|
||||
* Enabling VM_BIND will fail on devices which do not have per-process pgtables.
|
||||
* And it is not allowed to disable VM_BIND once it has been enabled.
|
||||
*
|
||||
* Enabling VM_BIND should be done (attempted) prior to allocating any BOs or
|
||||
* submitqueues of type MSM_SUBMITQUEUE_VM_BIND.
|
||||
*
|
||||
* Relatedly, when VM_BIND mode is enabled, the kernel will not try to recover
|
||||
* from GPU faults or failed async VM_BIND ops, in particular because it is
|
||||
* difficult to communicate to userspace which op failed so that userspace
|
||||
* could rewind and try again. When the VM is marked unusable, the SUBMIT
|
||||
* ioctl will throw -EPIPE.
|
||||
*/
|
||||
#define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */
|
||||
|
||||
/* For backwards compat. The original support for preemption was based on
|
||||
* a single ring per priority level so # of priority levels equals the #
|
||||
|
||||
Reference in New Issue
Block a user