forked from sonals/drm_sched_test
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sched_test_drv.c
231 lines (197 loc) · 5.97 KB
/
sched_test_drv.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021-2022 Xilinx, Inc.
* Authors:
* Sonal Santan <sonal.santan@xilinx.com>
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/gpu_scheduler.h>
#include "sched_test_common.h"
#include "uapi/sched_test.h"
#define DRIVER_NAME "sched_test"
#define DRIVER_DESC "DRM scheduler test driver"
#define DRIVER_DATE "20210815"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
static struct sched_test_device *sched_test_device_obj;
static int sched_test_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_gpu_scheduler *sched;
int ret = 0;
struct sched_test_file_priv *priv = kzalloc(sizeof(struct sched_test_file_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->sdev = to_sched_test_dev(dev);
sched = &priv->sdev->queue[SCHED_TSTQ_A].sched;
ret = drm_sched_entity_init(&priv->entity[SCHED_TSTQ_A], DRM_SCHED_PRIORITY_NORMAL, &sched,
1, NULL);
if (ret)
goto out;
sched = &priv->sdev->queue[SCHED_TSTQ_B].sched;
ret = drm_sched_entity_init(&priv->entity[SCHED_TSTQ_B], DRM_SCHED_PRIORITY_NORMAL, &sched,
1, NULL);
if (ret) {
drm_sched_entity_destroy(&priv->entity[SCHED_TSTQ_A]);
goto out;
}
idr_init_base(&priv->job_idr, 1);
file->driver_priv = priv;
drm_info(dev, "File opened...");
return 0;
out:
kfree(priv);
return ret;
}
static int job_idr_fini(int id, void *p, void *data)
{
struct sched_test_job *job = p;
sched_test_job_fini(job);
return 0;
}
static void sched_test_postclose(struct drm_device *dev, struct drm_file *file)
{
struct sched_test_file_priv *priv = file->driver_priv;
const bool outstanding = idr_is_empty(&priv->job_idr);
drm_info(dev, "File closing...");
if (!outstanding)
drm_info(dev, "Reap outstanding jobs...");
else
drm_info(dev, "No outstanding jobs...");
drm_sched_entity_destroy(&priv->entity[SCHED_TSTQ_B]);
drm_sched_entity_destroy(&priv->entity[SCHED_TSTQ_A]);
idr_for_each(&priv->job_idr, job_idr_fini, priv);
idr_destroy(&priv->job_idr);
kfree(priv);
drm_info(dev, "File closed!");
file->driver_priv = NULL;
}
int sched_test_submit_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct sched_test_file_priv *priv = file_priv->driver_priv;
union drm_sched_test_submit *args = data;
struct sched_test_job *in_job = NULL;
struct dma_fence *in_fence = NULL;
struct sched_test_job *job;
int ret = 0;
if (args->in.fence) {
in_job = idr_find(&priv->job_idr, args->in.fence);
in_fence = in_job ? in_job->done_fence : NULL;
}
job = kzalloc(sizeof(*job), GFP_KERNEL);
if (!job)
return -ENOMEM;
job->qu = args->in.qu;
ret = idr_alloc(&priv->job_idr, job, 1, 0, GFP_KERNEL);
if (ret > 0)
args->out.fence = ret;
else
goto out_free;
ret = sched_test_job_init(job, priv);
if (ret)
goto out_idr;
job->in_fence = dma_fence_get(in_fence);
return 0;
out_idr:
idr_remove(&priv->job_idr, args->out.fence);
out_free:
kfree(job);
args->out.fence = 0xffffffff;
return ret;
}
int sched_test_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct sched_test_file_priv *priv = file_priv->driver_priv;
union drm_sched_test_wait *args = data;
struct sched_test_job *job = idr_find(&priv->job_idr, args->in.fence);
signed long int left = 0;
if (!job)
return -EINVAL;
left = dma_fence_wait_timeout(job->done_fence, true, args->in.timeout);
if (left > 0) {
idr_remove(&priv->job_idr, args->in.fence);
sched_test_job_fini(job);
args->out.timeout = left;
return 0;
}
if (left < 0)
return left;
return -ETIMEDOUT;
}
static const struct drm_ioctl_desc sched_test_ioctls[] = {
DRM_IOCTL_DEF_DRV(SCHED_TEST_SUBMIT, sched_test_submit_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
DRM_IOCTL_DEF_DRV(SCHED_TEST_WAIT, sched_test_wait_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
};
DEFINE_DRM_GEM_FOPS(sched_test_driver_fops);
static struct drm_driver sched_test_driver = {
.driver_features = DRIVER_GEM | DRIVER_RENDER,
.open = sched_test_open,
.postclose = sched_test_postclose,
.ioctls = sched_test_ioctls,
.num_ioctls = ARRAY_SIZE(sched_test_ioctls),
.fops = &sched_test_driver_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
static int __init sched_test_init(void)
{
int ret;
struct platform_device *pdev = platform_device_register_simple("sched_test", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
ret = -ENOMEM;
goto out_unregister;
}
sched_test_device_obj = devm_drm_dev_alloc(&pdev->dev, &sched_test_driver,
struct sched_test_device, drm);
if (IS_ERR(sched_test_device_obj)) {
ret = PTR_ERR(sched_test_device_obj);
goto out_devres;
}
sched_test_device_obj->platform = pdev;
ret = sched_test_sched_init(sched_test_device_obj);
if (ret < 0)
goto out_devres;
ret = sched_test_hwemu_threads_start(sched_test_device_obj);
if (ret)
goto out_sched;
ret = drm_dev_register(&sched_test_device_obj->drm, 0);
if (ret)
goto out_hwemu;
return 0;
out_hwemu:
sched_test_hwemu_threads_stop(sched_test_device_obj);
out_sched:
sched_test_sched_fini(sched_test_device_obj);
out_devres:
devres_release_group(&pdev->dev, NULL);
out_unregister:
platform_device_unregister(pdev);
return ret;
}
static void __exit sched_test_exit(void)
{
struct platform_device *pdev = sched_test_device_obj->platform;
sched_test_hwemu_threads_stop(sched_test_device_obj);
drm_dev_unregister(&sched_test_device_obj->drm);
sched_test_sched_fini(sched_test_device_obj);
devres_release_group(&pdev->dev, NULL);
platform_device_unregister(pdev);
}
module_init(sched_test_init);
module_exit(sched_test_exit);
MODULE_AUTHOR("Sonal Santan <sonal.santan@xilinx.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL v2");