Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpu/drm/drm_ioctl.c
15111 views
1
/**
2
* \file drm_ioctl.c
3
* IOCTL processing for DRM
4
*
5
* \author Rickard E. (Rik) Faith <[email protected]>
6
* \author Gareth Hughes <[email protected]>
7
*/
8
9
/*
10
* Created: Fri Jan 8 09:01:26 1999 by [email protected]
11
*
12
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14
* All Rights Reserved.
15
*
16
* Permission is hereby granted, free of charge, to any person obtaining a
17
* copy of this software and associated documentation files (the "Software"),
18
* to deal in the Software without restriction, including without limitation
19
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
20
* and/or sell copies of the Software, and to permit persons to whom the
21
* Software is furnished to do so, subject to the following conditions:
22
*
23
* The above copyright notice and this permission notice (including the next
24
* paragraph) shall be included in all copies or substantial portions of the
25
* Software.
26
*
27
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33
* OTHER DEALINGS IN THE SOFTWARE.
34
*/
35
36
#include "drmP.h"
37
#include "drm_core.h"
38
39
#include "linux/pci.h"
40
41
/**
42
* Get the bus id.
43
*
44
* \param inode device inode.
45
* \param file_priv DRM file private.
46
* \param cmd command.
47
* \param arg user argument, pointing to a drm_unique structure.
48
* \return zero on success or a negative number on failure.
49
*
50
* Copies the bus id from drm_device::unique into user space.
51
*/
52
int drm_getunique(struct drm_device *dev, void *data,
53
struct drm_file *file_priv)
54
{
55
struct drm_unique *u = data;
56
struct drm_master *master = file_priv->master;
57
58
if (u->unique_len >= master->unique_len) {
59
if (copy_to_user(u->unique, master->unique, master->unique_len))
60
return -EFAULT;
61
}
62
u->unique_len = master->unique_len;
63
64
return 0;
65
}
66
67
static void
68
drm_unset_busid(struct drm_device *dev,
69
struct drm_master *master)
70
{
71
kfree(dev->devname);
72
dev->devname = NULL;
73
74
kfree(master->unique);
75
master->unique = NULL;
76
master->unique_len = 0;
77
master->unique_size = 0;
78
}
79
80
/**
81
* Set the bus id.
82
*
83
* \param inode device inode.
84
* \param file_priv DRM file private.
85
* \param cmd command.
86
* \param arg user argument, pointing to a drm_unique structure.
87
* \return zero on success or a negative number on failure.
88
*
89
* Copies the bus id from userspace into drm_device::unique, and verifies that
90
* it matches the device this DRM is attached to (EINVAL otherwise). Deprecated
91
* in interface version 1.1 and will return EBUSY when setversion has requested
92
* version 1.1 or greater.
93
*/
94
int drm_setunique(struct drm_device *dev, void *data,
95
struct drm_file *file_priv)
96
{
97
struct drm_unique *u = data;
98
struct drm_master *master = file_priv->master;
99
int ret;
100
101
if (master->unique_len || master->unique)
102
return -EBUSY;
103
104
if (!u->unique_len || u->unique_len > 1024)
105
return -EINVAL;
106
107
if (!dev->driver->bus->set_unique)
108
return -EINVAL;
109
110
ret = dev->driver->bus->set_unique(dev, master, u);
111
if (ret)
112
goto err;
113
114
return 0;
115
116
err:
117
drm_unset_busid(dev, master);
118
return ret;
119
}
120
121
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
122
{
123
struct drm_master *master = file_priv->master;
124
int ret;
125
126
if (master->unique != NULL)
127
drm_unset_busid(dev, master);
128
129
ret = dev->driver->bus->set_busid(dev, master);
130
if (ret)
131
goto err;
132
return 0;
133
err:
134
drm_unset_busid(dev, master);
135
return ret;
136
}
137
138
/**
139
* Get a mapping information.
140
*
141
* \param inode device inode.
142
* \param file_priv DRM file private.
143
* \param cmd command.
144
* \param arg user argument, pointing to a drm_map structure.
145
*
146
* \return zero on success or a negative number on failure.
147
*
148
* Searches for the mapping with the specified offset and copies its information
149
* into userspace
150
*/
151
int drm_getmap(struct drm_device *dev, void *data,
152
struct drm_file *file_priv)
153
{
154
struct drm_map *map = data;
155
struct drm_map_list *r_list = NULL;
156
struct list_head *list;
157
int idx;
158
int i;
159
160
idx = map->offset;
161
162
mutex_lock(&dev->struct_mutex);
163
if (idx < 0) {
164
mutex_unlock(&dev->struct_mutex);
165
return -EINVAL;
166
}
167
168
i = 0;
169
list_for_each(list, &dev->maplist) {
170
if (i == idx) {
171
r_list = list_entry(list, struct drm_map_list, head);
172
break;
173
}
174
i++;
175
}
176
if (!r_list || !r_list->map) {
177
mutex_unlock(&dev->struct_mutex);
178
return -EINVAL;
179
}
180
181
map->offset = r_list->map->offset;
182
map->size = r_list->map->size;
183
map->type = r_list->map->type;
184
map->flags = r_list->map->flags;
185
map->handle = (void *)(unsigned long) r_list->user_token;
186
map->mtrr = r_list->map->mtrr;
187
mutex_unlock(&dev->struct_mutex);
188
189
return 0;
190
}
191
192
/**
193
* Get client information.
194
*
195
* \param inode device inode.
196
* \param file_priv DRM file private.
197
* \param cmd command.
198
* \param arg user argument, pointing to a drm_client structure.
199
*
200
* \return zero on success or a negative number on failure.
201
*
202
* Searches for the client with the specified index and copies its information
203
* into userspace
204
*/
205
int drm_getclient(struct drm_device *dev, void *data,
206
struct drm_file *file_priv)
207
{
208
struct drm_client *client = data;
209
struct drm_file *pt;
210
int idx;
211
int i;
212
213
idx = client->idx;
214
mutex_lock(&dev->struct_mutex);
215
216
i = 0;
217
list_for_each_entry(pt, &dev->filelist, lhead) {
218
if (i++ >= idx) {
219
client->auth = pt->authenticated;
220
client->pid = pt->pid;
221
client->uid = pt->uid;
222
client->magic = pt->magic;
223
client->iocs = pt->ioctl_count;
224
mutex_unlock(&dev->struct_mutex);
225
226
return 0;
227
}
228
}
229
mutex_unlock(&dev->struct_mutex);
230
231
return -EINVAL;
232
}
233
234
/**
235
* Get statistics information.
236
*
237
* \param inode device inode.
238
* \param file_priv DRM file private.
239
* \param cmd command.
240
* \param arg user argument, pointing to a drm_stats structure.
241
*
242
* \return zero on success or a negative number on failure.
243
*/
244
int drm_getstats(struct drm_device *dev, void *data,
245
struct drm_file *file_priv)
246
{
247
struct drm_stats *stats = data;
248
int i;
249
250
memset(stats, 0, sizeof(*stats));
251
252
mutex_lock(&dev->struct_mutex);
253
254
for (i = 0; i < dev->counters; i++) {
255
if (dev->types[i] == _DRM_STAT_LOCK)
256
stats->data[i].value =
257
(file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);
258
else
259
stats->data[i].value = atomic_read(&dev->counts[i]);
260
stats->data[i].type = dev->types[i];
261
}
262
263
stats->count = dev->counters;
264
265
mutex_unlock(&dev->struct_mutex);
266
267
return 0;
268
}
269
270
/**
271
* Get device/driver capabilities
272
*/
273
int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
274
{
275
struct drm_get_cap *req = data;
276
277
req->value = 0;
278
switch (req->capability) {
279
case DRM_CAP_DUMB_BUFFER:
280
if (dev->driver->dumb_create)
281
req->value = 1;
282
break;
283
case DRM_CAP_VBLANK_HIGH_CRTC:
284
req->value = 1;
285
break;
286
default:
287
return -EINVAL;
288
}
289
return 0;
290
}
291
292
/**
293
* Setversion ioctl.
294
*
295
* \param inode device inode.
296
* \param file_priv DRM file private.
297
* \param cmd command.
298
* \param arg user argument, pointing to a drm_lock structure.
299
* \return zero on success or negative number on failure.
300
*
301
* Sets the requested interface version
302
*/
303
int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
304
{
305
struct drm_set_version *sv = data;
306
int if_version, retcode = 0;
307
308
if (sv->drm_di_major != -1) {
309
if (sv->drm_di_major != DRM_IF_MAJOR ||
310
sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
311
retcode = -EINVAL;
312
goto done;
313
}
314
if_version = DRM_IF_VERSION(sv->drm_di_major,
315
sv->drm_di_minor);
316
dev->if_version = max(if_version, dev->if_version);
317
if (sv->drm_di_minor >= 1) {
318
/*
319
* Version 1.1 includes tying of DRM to specific device
320
* Version 1.4 has proper PCI domain support
321
*/
322
retcode = drm_set_busid(dev, file_priv);
323
if (retcode)
324
goto done;
325
}
326
}
327
328
if (sv->drm_dd_major != -1) {
329
if (sv->drm_dd_major != dev->driver->major ||
330
sv->drm_dd_minor < 0 || sv->drm_dd_minor >
331
dev->driver->minor) {
332
retcode = -EINVAL;
333
goto done;
334
}
335
336
if (dev->driver->set_version)
337
dev->driver->set_version(dev, sv);
338
}
339
340
done:
341
sv->drm_di_major = DRM_IF_MAJOR;
342
sv->drm_di_minor = DRM_IF_MINOR;
343
sv->drm_dd_major = dev->driver->major;
344
sv->drm_dd_minor = dev->driver->minor;
345
346
return retcode;
347
}
348
349
/** No-op ioctl. */
350
int drm_noop(struct drm_device *dev, void *data,
351
struct drm_file *file_priv)
352
{
353
DRM_DEBUG("\n");
354
return 0;
355
}
356
357