brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 0e80312 Raw
308 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2017 The Linux Foundation. All rights reserved.3 */4 5#include <linux/kref.h>6#include <linux/uaccess.h>7 8#include "msm_gpu.h"9 10int msm_file_private_set_sysprof(struct msm_file_private *ctx,11				 struct msm_gpu *gpu, int sysprof)12{13	/*14	 * Since pm_runtime and sysprof_active are both refcounts, we15	 * call apply the new value first, and then unwind the previous16	 * value17	 */18 19	switch (sysprof) {20	default:21		return -EINVAL;22	case 2:23		pm_runtime_get_sync(&gpu->pdev->dev);24		fallthrough;25	case 1:26		refcount_inc(&gpu->sysprof_active);27		fallthrough;28	case 0:29		break;30	}31 32	/* unwind old value: */33	switch (ctx->sysprof) {34	case 2:35		pm_runtime_put_autosuspend(&gpu->pdev->dev);36		fallthrough;37	case 1:38		refcount_dec(&gpu->sysprof_active);39		fallthrough;40	case 0:41		break;42	}43 44	ctx->sysprof = sysprof;45 46	return 0;47}48 49void __msm_file_private_destroy(struct kref *kref)50{51	struct msm_file_private *ctx = container_of(kref,52		struct msm_file_private, ref);53	int i;54 55	for (i = 0; i < ARRAY_SIZE(ctx->entities); i++) {56		if (!ctx->entities[i])57			continue;58 59		drm_sched_entity_destroy(ctx->entities[i]);60		kfree(ctx->entities[i]);61	}62 63	msm_gem_address_space_put(ctx->aspace);64	kfree(ctx->comm);65	kfree(ctx->cmdline);66	kfree(ctx);67}68 69void msm_submitqueue_destroy(struct kref *kref)70{71	struct msm_gpu_submitqueue *queue = container_of(kref,72		struct msm_gpu_submitqueue, ref);73 74	idr_destroy(&queue->fence_idr);75 76	msm_file_private_put(queue->ctx);77 78	kfree(queue);79}80 81struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx,82		u32 id)83{84	struct msm_gpu_submitqueue *entry;85 86	if (!ctx)87		return NULL;88 89	read_lock(&ctx->queuelock);90 91	list_for_each_entry(entry, &ctx->submitqueues, node) {92		if (entry->id == id) {93			kref_get(&entry->ref);94			read_unlock(&ctx->queuelock);95 96			return entry;97		}98	}99 100	read_unlock(&ctx->queuelock);101	return NULL;102}103 104void msm_submitqueue_close(struct msm_file_private *ctx)105{106	struct msm_gpu_submitqueue *entry, *tmp;107 108	if (!ctx)109		return;110 111	/*112	 * No lock needed in close and there won't113	 * be any more user ioctls coming our way114	 */115	list_for_each_entry_safe(entry, tmp, &ctx->submitqueues, node) {116		list_del(&entry->node);117		msm_submitqueue_put(entry);118	}119}120 121static struct drm_sched_entity *122get_sched_entity(struct msm_file_private *ctx, struct msm_ringbuffer *ring,123		 unsigned ring_nr, enum drm_sched_priority sched_prio)124{125	static DEFINE_MUTEX(entity_lock);126	unsigned idx = (ring_nr * NR_SCHED_PRIORITIES) + sched_prio;127 128	/* We should have already validated that the requested priority is129	 * valid by the time we get here.130	 */131	if (WARN_ON(idx >= ARRAY_SIZE(ctx->entities)))132		return ERR_PTR(-EINVAL);133 134	mutex_lock(&entity_lock);135 136	if (!ctx->entities[idx]) {137		struct drm_sched_entity *entity;138		struct drm_gpu_scheduler *sched = &ring->sched;139		int ret;140 141		entity = kzalloc(sizeof(*ctx->entities[idx]), GFP_KERNEL);142 143		ret = drm_sched_entity_init(entity, sched_prio, &sched, 1, NULL);144		if (ret) {145			mutex_unlock(&entity_lock);146			kfree(entity);147			return ERR_PTR(ret);148		}149 150		ctx->entities[idx] = entity;151	}152 153	mutex_unlock(&entity_lock);154 155	return ctx->entities[idx];156}157 158int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,159		u32 prio, u32 flags, u32 *id)160{161	struct msm_drm_private *priv = drm->dev_private;162	struct msm_gpu_submitqueue *queue;163	enum drm_sched_priority sched_prio;164	unsigned ring_nr;165	int ret;166 167	if (!ctx)168		return -ENODEV;169 170	if (!priv->gpu)171		return -ENODEV;172 173	ret = msm_gpu_convert_priority(priv->gpu, prio, &ring_nr, &sched_prio);174	if (ret)175		return ret;176 177	queue = kzalloc(sizeof(*queue), GFP_KERNEL);178 179	if (!queue)180		return -ENOMEM;181 182	kref_init(&queue->ref);183	queue->flags = flags;184	queue->ring_nr = ring_nr;185 186	queue->entity = get_sched_entity(ctx, priv->gpu->rb[ring_nr],187					 ring_nr, sched_prio);188	if (IS_ERR(queue->entity)) {189		ret = PTR_ERR(queue->entity);190		kfree(queue);191		return ret;192	}193 194	write_lock(&ctx->queuelock);195 196	queue->ctx = msm_file_private_get(ctx);197	queue->id = ctx->queueid++;198 199	if (id)200		*id = queue->id;201 202	idr_init(&queue->fence_idr);203	spin_lock_init(&queue->idr_lock);204	mutex_init(&queue->lock);205 206	list_add_tail(&queue->node, &ctx->submitqueues);207 208	write_unlock(&ctx->queuelock);209 210	return 0;211}212 213/*214 * Create the default submit-queue (id==0), used for backwards compatibility215 * for userspace that pre-dates the introduction of submitqueues.216 */217int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx)218{219	struct msm_drm_private *priv = drm->dev_private;220	int default_prio, max_priority;221 222	if (!priv->gpu)223		return -ENODEV;224 225	max_priority = (priv->gpu->nr_rings * NR_SCHED_PRIORITIES) - 1;226 227	/*228	 * Pick a medium priority level as default.  Lower numeric value is229	 * higher priority, so round-up to pick a priority that is not higher230	 * than the middle priority level.231	 */232	default_prio = DIV_ROUND_UP(max_priority, 2);233 234	return msm_submitqueue_create(drm, ctx, default_prio, 0, NULL);235}236 237static int msm_submitqueue_query_faults(struct msm_gpu_submitqueue *queue,238		struct drm_msm_submitqueue_query *args)239{240	size_t size = min_t(size_t, args->len, sizeof(queue->faults));241	int ret;242 243	/* If a zero length was passed in, return the data size we expect */244	if (!args->len) {245		args->len = sizeof(queue->faults);246		return 0;247	}248 249	/* Set the length to the actual size of the data */250	args->len = size;251 252	ret = copy_to_user(u64_to_user_ptr(args->data), &queue->faults, size);253 254	return ret ? -EFAULT : 0;255}256 257int msm_submitqueue_query(struct drm_device *drm, struct msm_file_private *ctx,258		struct drm_msm_submitqueue_query *args)259{260	struct msm_gpu_submitqueue *queue;261	int ret = -EINVAL;262 263	if (args->pad)264		return -EINVAL;265 266	queue = msm_submitqueue_get(ctx, args->id);267	if (!queue)268		return -ENOENT;269 270	if (args->param == MSM_SUBMITQUEUE_PARAM_FAULTS)271		ret = msm_submitqueue_query_faults(queue, args);272 273	msm_submitqueue_put(queue);274 275	return ret;276}277 278int msm_submitqueue_remove(struct msm_file_private *ctx, u32 id)279{280	struct msm_gpu_submitqueue *entry;281 282	if (!ctx)283		return 0;284 285	/*286	 * id 0 is the "default" queue and can't be destroyed287	 * by the user288	 */289	if (!id)290		return -ENOENT;291 292	write_lock(&ctx->queuelock);293 294	list_for_each_entry(entry, &ctx->submitqueues, node) {295		if (entry->id == id) {296			list_del(&entry->node);297			write_unlock(&ctx->queuelock);298 299			msm_submitqueue_put(entry);300			return 0;301		}302	}303 304	write_unlock(&ctx->queuelock);305	return -ENOENT;306}307 308