1f7de1545SJordan Crouse /* Copyright (c) 2017 The Linux Foundation. All rights reserved.
2f7de1545SJordan Crouse  *
3f7de1545SJordan Crouse  * This program is free software; you can redistribute it and/or modify
4f7de1545SJordan Crouse  * it under the terms of the GNU General Public License version 2 and
5f7de1545SJordan Crouse  * only version 2 as published by the Free Software Foundation.
6f7de1545SJordan Crouse  *
7f7de1545SJordan Crouse  * This program is distributed in the hope that it will be useful,
8f7de1545SJordan Crouse  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9f7de1545SJordan Crouse  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10f7de1545SJordan Crouse  * GNU General Public License for more details.
11f7de1545SJordan Crouse  *
12f7de1545SJordan Crouse  */
13f7de1545SJordan Crouse 
14f7de1545SJordan Crouse #include <linux/kref.h>
15f7de1545SJordan Crouse #include "msm_gpu.h"
16f7de1545SJordan Crouse 
17f7de1545SJordan Crouse void msm_submitqueue_destroy(struct kref *kref)
18f7de1545SJordan Crouse {
19f7de1545SJordan Crouse 	struct msm_gpu_submitqueue *queue = container_of(kref,
20f7de1545SJordan Crouse 		struct msm_gpu_submitqueue, ref);
21f7de1545SJordan Crouse 
22f7de1545SJordan Crouse 	kfree(queue);
23f7de1545SJordan Crouse }
24f7de1545SJordan Crouse 
25f7de1545SJordan Crouse struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_file_private *ctx,
26f7de1545SJordan Crouse 		u32 id)
27f7de1545SJordan Crouse {
28f7de1545SJordan Crouse 	struct msm_gpu_submitqueue *entry;
29f7de1545SJordan Crouse 
30f7de1545SJordan Crouse 	if (!ctx)
31f7de1545SJordan Crouse 		return NULL;
32f7de1545SJordan Crouse 
33f7de1545SJordan Crouse 	read_lock(&ctx->queuelock);
34f7de1545SJordan Crouse 
35f7de1545SJordan Crouse 	list_for_each_entry(entry, &ctx->submitqueues, node) {
36f7de1545SJordan Crouse 		if (entry->id == id) {
37f7de1545SJordan Crouse 			kref_get(&entry->ref);
38f7de1545SJordan Crouse 			read_unlock(&ctx->queuelock);
39f7de1545SJordan Crouse 
40f7de1545SJordan Crouse 			return entry;
41f7de1545SJordan Crouse 		}
42f7de1545SJordan Crouse 	}
43f7de1545SJordan Crouse 
44f7de1545SJordan Crouse 	read_unlock(&ctx->queuelock);
45f7de1545SJordan Crouse 	return NULL;
46f7de1545SJordan Crouse }
47f7de1545SJordan Crouse 
48f7de1545SJordan Crouse void msm_submitqueue_close(struct msm_file_private *ctx)
49f7de1545SJordan Crouse {
50f7de1545SJordan Crouse 	struct msm_gpu_submitqueue *entry, *tmp;
51f7de1545SJordan Crouse 
52f7de1545SJordan Crouse 	if (!ctx)
53f7de1545SJordan Crouse 		return;
54f7de1545SJordan Crouse 
55f7de1545SJordan Crouse 	/*
56f7de1545SJordan Crouse 	 * No lock needed in close and there won't
57f7de1545SJordan Crouse 	 * be any more user ioctls coming our way
58f7de1545SJordan Crouse 	 */
59f7de1545SJordan Crouse 	list_for_each_entry_safe(entry, tmp, &ctx->submitqueues, node)
60f7de1545SJordan Crouse 		msm_submitqueue_put(entry);
61f7de1545SJordan Crouse }
62f7de1545SJordan Crouse 
63f97decacSJordan Crouse int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,
64f97decacSJordan Crouse 		u32 prio, u32 flags, u32 *id)
65f7de1545SJordan Crouse {
66f97decacSJordan Crouse 	struct msm_drm_private *priv = drm->dev_private;
67f7de1545SJordan Crouse 	struct msm_gpu_submitqueue *queue;
68f7de1545SJordan Crouse 
69f7de1545SJordan Crouse 	if (!ctx)
70f7de1545SJordan Crouse 		return -ENODEV;
71f7de1545SJordan Crouse 
72f7de1545SJordan Crouse 	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
73f7de1545SJordan Crouse 
74f7de1545SJordan Crouse 	if (!queue)
75f7de1545SJordan Crouse 		return -ENOMEM;
76f7de1545SJordan Crouse 
77f7de1545SJordan Crouse 	kref_init(&queue->ref);
78f7de1545SJordan Crouse 	queue->flags = flags;
79f97decacSJordan Crouse 
80f97decacSJordan Crouse 	if (priv->gpu) {
81f97decacSJordan Crouse 		if (prio >= priv->gpu->nr_rings)
82f97decacSJordan Crouse 			return -EINVAL;
83f97decacSJordan Crouse 
84f7de1545SJordan Crouse 		queue->prio = prio;
85f97decacSJordan Crouse 	}
86f7de1545SJordan Crouse 
87f7de1545SJordan Crouse 	write_lock(&ctx->queuelock);
88f7de1545SJordan Crouse 
89f7de1545SJordan Crouse 	queue->id = ctx->queueid++;
90f7de1545SJordan Crouse 
91f7de1545SJordan Crouse 	if (id)
92f7de1545SJordan Crouse 		*id = queue->id;
93f7de1545SJordan Crouse 
94f7de1545SJordan Crouse 	list_add_tail(&queue->node, &ctx->submitqueues);
95f7de1545SJordan Crouse 
96f7de1545SJordan Crouse 	write_unlock(&ctx->queuelock);
97f7de1545SJordan Crouse 
98f7de1545SJordan Crouse 	return 0;
99f7de1545SJordan Crouse }
100f7de1545SJordan Crouse 
101f97decacSJordan Crouse int msm_submitqueue_init(struct drm_device *drm, struct msm_file_private *ctx)
102f7de1545SJordan Crouse {
103f97decacSJordan Crouse 	struct msm_drm_private *priv = drm->dev_private;
104f97decacSJordan Crouse 	int default_prio;
105f97decacSJordan Crouse 
106f7de1545SJordan Crouse 	if (!ctx)
107f7de1545SJordan Crouse 		return 0;
108f7de1545SJordan Crouse 
109f97decacSJordan Crouse 	/*
110f97decacSJordan Crouse 	 * Select priority 2 as the "default priority" unless nr_rings is less
111f97decacSJordan Crouse 	 * than 2 and then pick the lowest pirority
112f97decacSJordan Crouse 	 */
113f97decacSJordan Crouse 	default_prio = priv->gpu ?
114f97decacSJordan Crouse 		clamp_t(uint32_t, 2, 0, priv->gpu->nr_rings - 1) : 0;
115f97decacSJordan Crouse 
116f7de1545SJordan Crouse 	INIT_LIST_HEAD(&ctx->submitqueues);
117f7de1545SJordan Crouse 
118f7de1545SJordan Crouse 	rwlock_init(&ctx->queuelock);
119f7de1545SJordan Crouse 
120f97decacSJordan Crouse 	return msm_submitqueue_create(drm, ctx, default_prio, 0, NULL);
121f7de1545SJordan Crouse }
122f7de1545SJordan Crouse 
123f7de1545SJordan Crouse int msm_submitqueue_remove(struct msm_file_private *ctx, u32 id)
124f7de1545SJordan Crouse {
125f7de1545SJordan Crouse 	struct msm_gpu_submitqueue *entry;
126f7de1545SJordan Crouse 
127f7de1545SJordan Crouse 	if (!ctx)
128f7de1545SJordan Crouse 		return 0;
129f7de1545SJordan Crouse 
130f7de1545SJordan Crouse 	/*
131f7de1545SJordan Crouse 	 * id 0 is the "default" queue and can't be destroyed
132f7de1545SJordan Crouse 	 * by the user
133f7de1545SJordan Crouse 	 */
134f7de1545SJordan Crouse 	if (!id)
135f7de1545SJordan Crouse 		return -ENOENT;
136f7de1545SJordan Crouse 
137f7de1545SJordan Crouse 	write_lock(&ctx->queuelock);
138f7de1545SJordan Crouse 
139f7de1545SJordan Crouse 	list_for_each_entry(entry, &ctx->submitqueues, node) {
140f7de1545SJordan Crouse 		if (entry->id == id) {
141f7de1545SJordan Crouse 			list_del(&entry->node);
142f7de1545SJordan Crouse 			write_unlock(&ctx->queuelock);
143f7de1545SJordan Crouse 
144f7de1545SJordan Crouse 			msm_submitqueue_put(entry);
145f7de1545SJordan Crouse 			return 0;
146f7de1545SJordan Crouse 		}
147f7de1545SJordan Crouse 	}
148f7de1545SJordan Crouse 
149f7de1545SJordan Crouse 	write_unlock(&ctx->queuelock);
150f7de1545SJordan Crouse 	return -ENOENT;
151f7de1545SJordan Crouse }
152f7de1545SJordan Crouse 
153