/* For userspace errors, use DRM_UT_DRIVER.. so that userspace can enable *errormsgsfordebugging,butwedon'tspamdmesgbydefault
*/ #define SUBMIT_ERROR(err, submit, fmt, ...) \
UERR(err, (submit)->dev, fmt, ##__VA_ARGS__)
for (i = 0; i < args->nr_bos; i++) { struct drm_gem_object *obj;
/* normally use drm_gem_object_lookup(), but for bulk lookup *allundersingletable_lockjusthitobject_idrdirectly:
*/
obj = idr_find(&file->object_idr, submit->bos[i].handle); if (!obj) {
ret = SUBMIT_ERROR(EINVAL, submit, "invalid handle %u at index %u\n", submit->bos[i].handle, i); goto out_unlock;
}
drm_exec_until_all_locked (&submit->exec) {
ret = drm_gpuvm_prepare_vm(submit->vm, exec, 1);
drm_exec_retry_on_contention(exec); if (ret) break;
ret = drm_gpuvm_prepare_objects(submit->vm, exec, 1);
drm_exec_retry_on_contention(exec); if (ret) break;
}
return ret;
}
/* This is where we make sure all the bo's are reserved and pin'd: */ staticint submit_lock_objects(struct msm_gem_submit *submit)
{ unsigned flags = DRM_EXEC_INTERRUPTIBLE_WAIT; int ret = 0;
if (msm_context_is_vmbind(submit->queue->ctx)) return submit_lock_objects_vmbind(submit);
drm_exec_until_all_locked (&submit->exec) {
ret = drm_exec_lock_obj(&submit->exec,
drm_gpuvm_resv_obj(submit->vm));
drm_exec_retry_on_contention(&submit->exec); if (ret) break; for (unsigned i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj;
ret = drm_exec_prepare_obj(&submit->exec, obj, 1);
drm_exec_retry_on_contention(&submit->exec); if (ret) break;
}
}
return ret;
}
staticint submit_fence_sync(struct msm_gem_submit *submit)
{ int i, ret = 0;
for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE;
/* Otherwise userspace can ask for implicit sync to be *disabledonspecificbuffers.Thisisusefulforinternal *usermodedrivermanagedbuffers,suballocation,etc.
*/ if (submit->bos[i].flags & MSM_SUBMIT_BO_NO_IMPLICIT) continue;
ret = drm_sched_job_add_implicit_dependencies(&submit->base,
obj,
write); if (ret) break;
}
return ret;
}
staticint submit_pin_objects(struct msm_gem_submit *submit)
{ struct msm_drm_private *priv = submit->dev->dev_private; int i, ret = 0;
for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; struct drm_gpuva *vma;
/* if locking succeeded, pin bo: */
vma = msm_gem_get_vma_locked(obj, submit->vm); if (IS_ERR(vma)) {
ret = PTR_ERR(vma); break;
}
ret = msm_gem_pin_vma_locked(obj, vma); if (ret) break;
if (obj)
*obj = submit->bos[idx].obj; if (iova)
*iova = submit->bos[idx].iova;
return0;
}
/* process the reloc's and patch up the cmdstream as needed: */ staticint submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *obj,
uint32_t offset, uint32_t nr_relocs, struct drm_msm_gem_submit_reloc *relocs)
{
uint32_t i, last_offset = 0;
uint32_t *ptr; int ret = 0;
/* Cleanup submit at end of ioctl. In the error case, this also drops *references,unpins,anddropsactiverefcnt.Inthenon-errorcase, *thisisdonewhenthesubmitisretired.
*/ staticvoid submit_cleanup(struct msm_gem_submit *submit, bool error)
{ if (error)
submit_unpin_objects(submit);
if (submit->exec.objects)
drm_exec_fini(&submit->exec);
/* if job wasn't enqueued to scheduler, early retirement: */ if (error)
msm_submit_retire(submit);
}
void msm_submit_retire(struct msm_gem_submit *submit)
{ int i;
for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; struct drm_gpuvm_bo *vm_bo = submit->bos[i].vm_bo;
if (to_msm_vm(ctx->vm)->unusable) return UERR(EPIPE, dev, "context is unusable");
/* for now, we just have 3d pipe.. eventually this would need to *bemoreclevertodispatchtoappropriategpumodule:
*/ if (MSM_PIPE_ID(args->flags) != MSM_PIPE_3D0) return UERR(EINVAL, dev, "invalid pipe");
if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS) return UERR(EINVAL, dev, "invalid flags");
if (args->flags & MSM_SUBMIT_SUDO) { if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) ||
!capable(CAP_SYS_RAWIO)) return -EINVAL;
}
queue = msm_submitqueue_get(ctx, args->queueid); if (!queue) return -ENOENT;
if (queue->flags & MSM_SUBMITQUEUE_VM_BIND) {
ret = UERR(EINVAL, dev, "Invalid queue type"); goto out_post_unlock;
}
ring = gpu->rb[queue->ring_nr];
if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
out_fence_fd = get_unused_fd_flags(O_CLOEXEC); if (out_fence_fd < 0) {
ret = out_fence_fd; goto out_post_unlock;
}
}
submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds,
file->client_id); if (IS_ERR(submit)) {
ret = PTR_ERR(submit); goto out_post_unlock;
}
out:
submit_cleanup(submit, !!ret);
out_unlock:
mutex_unlock(&queue->lock);
out_post_unlock: if (ret) { if (out_fence_fd >= 0)
put_unused_fd(out_fence_fd); if (sync_file)
fput(sync_file->file);
} elseif (sync_file) {
fd_install(out_fence_fd, sync_file->file);
args->fence_fd = out_fence_fd;
}
if (!IS_ERR_OR_NULL(submit)) {
msm_gem_submit_put(submit);
} else { /* *Ifthesubmithasn'tyettakenownershipofthequeue *thenweneedtodropthereferenceourself:
*/
msm_submitqueue_put(queue);
} if (!IS_ERR_OR_NULL(post_deps)) { for (i = 0; i < args->nr_out_syncobjs; ++i) {
kfree(post_deps[i].chain);
drm_syncobj_put(post_deps[i].syncobj);
}
kfree(post_deps);
}
if (!IS_ERR_OR_NULL(syncobjs_to_reset)) { for (i = 0; i < args->nr_in_syncobjs; ++i) { if (syncobjs_to_reset[i])
drm_syncobj_put(syncobjs_to_reset[i]);
}
kfree(syncobjs_to_reset);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.