xref: /titanic_50/usr/src/uts/common/io/drm/drm_ioctl.c (revision bde3d612a7c090234c60e6e4578821237a5db135)
1 /*
2  * drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*-
3  * Created: Fri Jan  8 09:01:26 1999 by faith@valinux.com
4  */
5 /*
6  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
7  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
8  * All Rights Reserved.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice (including the next
18  * paragraph) shall be included in all copies or substantial portions of the
19  * Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  * OTHER DEALINGS IN THE SOFTWARE.
28  *
29  * Authors:
30  *    Rickard E. (Rik) Faith <faith@valinux.com>
31  *    Gareth Hughes <gareth@valinux.com>
32  *
33  */
34 
35 /*
36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "drmP.h"
43 #include "drm_io32.h"
44 
45 /*
46  * Beginning in revision 1.1 of the DRM interface, getunique will return
47  * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
48  * before setunique has been called.  The format for the bus-specific part of
49  * the unique is not defined for any other bus.
50  */
51 /*ARGSUSED*/
52 int
53 drm_getunique(DRM_IOCTL_ARGS)
54 {
55 	DRM_DEVICE;
56 	drm_unique_t	 u1;
57 
58 #ifdef	_MULTI_DATAMODEL
59 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
60 		drm_unique_32_t u32;
61 
62 		DRM_COPYFROM_WITH_RETURN(&u32, (void *)data, sizeof (u32));
63 		u1.unique_len = u32.unique_len;
64 		u1.unique = (char __user *)(uintptr_t)u32.unique;
65 	} else
66 #endif
67 		DRM_COPYFROM_WITH_RETURN(&u1, (void *)data, sizeof (u1));
68 
69 	if (u1.unique_len >= dev->unique_len) {
70 		if (dev->unique_len == 0) {
71 			DRM_ERROR("drm_getunique: dev->unique_len = 0");
72 			return (EFAULT);
73 		}
74 		if (DRM_COPY_TO_USER(u1.unique, dev->unique, dev->unique_len))
75 			return (EFAULT);
76 	}
77 	u1.unique_len = dev->unique_len;
78 
79 #ifdef	_MULTI_DATAMODEL
80 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
81 		drm_unique_32_t u32;
82 
83 		u32.unique_len = (uint32_t)u1.unique_len;
84 		u32.unique = (caddr32_t)(uintptr_t)u1.unique;
85 		DRM_COPYTO_WITH_RETURN((void *)data, &u32, sizeof (u32));
86 	} else
87 #endif
88 		DRM_COPYTO_WITH_RETURN((void *)data, &u1, sizeof (u1));
89 
90 	return (0);
91 }
92 
93 /*
94  * Deprecated in DRM version 1.1, and will return EBUSY when setversion has
95  * requested version 1.1 or greater.
96  */
97 /*ARGSUSED*/
98 int
99 drm_setunique(DRM_IOCTL_ARGS)
100 {
101 	return (EINVAL);
102 }
103 
104 
105 static int
106 drm_set_busid(drm_device_t *dev)
107 {
108 	DRM_LOCK();
109 
110 	if (dev->unique != NULL) {
111 		DRM_UNLOCK();
112 		return (EBUSY);
113 	}
114 
115 	dev->unique_len = 20;
116 	dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
117 	if (dev->unique == NULL) {
118 		DRM_UNLOCK();
119 		return (ENOMEM);
120 	}
121 
122 	(void) snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
123 	    dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
124 
125 	DRM_UNLOCK();
126 
127 	return (0);
128 }
129 
130 /*ARGSUSED*/
131 int
132 drm_getmap(DRM_IOCTL_ARGS)
133 {
134 	DRM_DEVICE;
135 	drm_map_t	map;
136 	drm_local_map_t    *mapinlist;
137 	int		idx;
138 	int		i = 0;
139 
140 #ifdef	_MULTI_DATAMODEL
141 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
142 		drm_map_32_t map32;
143 
144 		DRM_COPYFROM_WITH_RETURN(&map32, (void *)data, sizeof (map32));
145 		map.offset = map32.offset;
146 		map.size = map32.size;
147 		map.type = map32.type;
148 		map.flags = map32.flags;
149 		map.handle = map32.handle;
150 		map.mtrr = map32.mtrr;
151 	} else
152 #endif
153 		DRM_COPYFROM_WITH_RETURN(&map, (void *)data, sizeof (map));
154 
155 	idx = (int)map.offset;
156 
157 	DRM_LOCK();
158 	if (idx < 0) {
159 		DRM_UNLOCK();
160 		return (EINVAL);
161 	}
162 
163 	TAILQ_FOREACH(mapinlist, &dev->maplist, link) {
164 		if (i == idx) {
165 			map.offset = mapinlist->offset;
166 			map.size   = mapinlist->size;
167 			map.type   = mapinlist->type;
168 			map.flags  = mapinlist->flags;
169 			map.handle = (unsigned long long)(uintptr_t)
170 			    mapinlist->handle;
171 			map.mtrr   = mapinlist->mtrr;
172 			break;
173 		}
174 		i++;
175 	}
176 
177 	DRM_UNLOCK();
178 
179 	if (mapinlist == NULL)
180 		return (EINVAL);
181 
182 #ifdef	_MULTI_DATAMODEL
183 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
184 		drm_map_32_t map32;
185 
186 		map32.offset = map.offset;
187 		map32.size = (uint32_t)map.size;
188 		map32.type = map.type;
189 		map32.flags = map.flags;
190 		map32.handle = (uintptr_t)map.handle;
191 		map32.mtrr = map.mtrr;
192 		DRM_COPYTO_WITH_RETURN((void *)data, &map32, sizeof (map32));
193 	} else
194 #endif
195 		DRM_COPYTO_WITH_RETURN((void *)data, &map, sizeof (map));
196 
197 	return (0);
198 }
199 
200 /*ARGSUSED*/
201 int
202 drm_getclient(DRM_IOCTL_ARGS)
203 {
204 	DRM_DEVICE;
205 	drm_client_t	client;
206 	drm_file_t	*pt;
207 	int		idx;
208 	int		i = 0;
209 
210 #ifdef	_MULTI_DATAMODEL
211 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
212 		drm_client_32_t client32;
213 
214 		DRM_COPYFROM_WITH_RETURN(&client32, (void *)data,
215 		    sizeof (client32));
216 		client.idx = client32.idx;
217 		client.auth = client32.auth;
218 		client.pid = client32.pid;
219 		client.uid = client32.uid;
220 		client.magic = client32.magic;
221 		client.iocs = client32.iocs;
222 	} else
223 #endif
224 		DRM_COPYFROM_WITH_RETURN(&client, (void *)data,
225 		    sizeof (client));
226 
227 	idx = client.idx;
228 	DRM_LOCK();
229 	TAILQ_FOREACH(pt, &dev->files, link) {
230 		if (i == idx) {
231 			client.auth  = pt->authenticated;
232 			client.pid   = pt->pid;
233 			client.uid   = pt->uid;
234 			client.magic = pt->magic;
235 			client.iocs  = pt->ioctl_count;
236 			DRM_UNLOCK();
237 
238 #ifdef	_MULTI_DATAMODEL
239 			if (ddi_model_convert_from(mode & FMODELS) ==
240 			    DDI_MODEL_ILP32) {
241 				drm_client_32_t client32;
242 
243 				client32.idx = client.idx;
244 				client32.auth = client.auth;
245 				client32.pid = (uint32_t)client.pid;
246 				client32.uid = (uint32_t)client.uid;
247 				client32.magic = (uint32_t)client.magic;
248 				client32.iocs = (uint32_t)client.iocs;
249 
250 				DRM_COPYTO_WITH_RETURN((void *)data, &client32,
251 				    sizeof (client32));
252 			} else
253 #endif
254 				DRM_COPYTO_WITH_RETURN((void *)data,
255 				    &client, sizeof (client));
256 
257 			return (0);
258 		}
259 		i++;
260 	}
261 	DRM_UNLOCK();
262 	return (EINVAL);
263 }
264 
265 /*ARGSUSED*/
266 int
267 drm_getstats(DRM_IOCTL_ARGS)
268 {
269 	DRM_DEVICE;
270 	drm_stats_t	stats;
271 	int		i;
272 
273 	bzero(&stats, sizeof (stats));
274 
275 	DRM_LOCK();
276 
277 	for (i = 0; i < dev->counters; i++) {
278 		if (dev->types[i] == _DRM_STAT_LOCK) {
279 			stats.data[i].value
280 			    = (dev->lock.hw_lock
281 			    ? dev->lock.hw_lock->lock : 0);
282 		} else
283 			stats.data[i].value = atomic_read(&dev->counts[i]);
284 		stats.data[i].type  = dev->types[i];
285 	}
286 
287 	stats.count = dev->counters;
288 
289 	DRM_UNLOCK();
290 
291 #ifdef	_MULTI_DATAMODEL
292 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
293 		drm_stats_32_t stats32;
294 		stats32.count = (uint32_t)stats.count;
295 		for (i = 0; i < 15; i++) {
296 			stats32.data[i].value = stats.data[i].value;
297 			stats32.data[i].type = stats.data[i].type;
298 		}
299 		DRM_COPYTO_WITH_RETURN((void *)data, &stats32,
300 		    sizeof (stats32));
301 	} else
302 #endif
303 		DRM_COPYTO_WITH_RETURN((void *)data, &stats, sizeof (stats));
304 
305 	return (0);
306 }
307 
308 #define	DRM_IF_MAJOR	1
309 #define	DRM_IF_MINOR	2
310 
311 /*ARGSUSED*/
312 int
313 drm_setversion(DRM_IOCTL_ARGS)
314 {
315 	DRM_DEVICE;
316 	drm_set_version_t sv;
317 	drm_set_version_t retv;
318 	int if_version;
319 
320 	DRM_COPYFROM_WITH_RETURN(&sv, (void *)data, sizeof (sv));
321 
322 	retv.drm_di_major = DRM_IF_MAJOR;
323 	retv.drm_di_minor = DRM_IF_MINOR;
324 	retv.drm_dd_major = dev->driver->driver_major;
325 	retv.drm_dd_minor = dev->driver->driver_minor;
326 
327 	DRM_COPYTO_WITH_RETURN((void *)data, &retv, sizeof (sv));
328 
329 	if (sv.drm_di_major != -1) {
330 		if (sv.drm_di_major != DRM_IF_MAJOR ||
331 		    sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
332 			return (EINVAL);
333 		if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
334 		dev->if_version = DRM_MAX(if_version, dev->if_version);
335 		if (sv.drm_di_minor >= 1) {
336 			/*
337 			 * Version 1.1 includes tying of DRM to specific device
338 			 */
339 			(void) drm_set_busid(dev);
340 		}
341 	}
342 
343 	if (sv.drm_dd_major != -1) {
344 		if (sv.drm_dd_major != dev->driver->driver_major ||
345 		    sv.drm_dd_minor < 0 ||
346 		    sv.drm_dd_minor > dev->driver->driver_minor)
347 			return (EINVAL);
348 	}
349 	return (0);
350 }
351 
352 
353 /*ARGSUSED*/
354 int
355 drm_noop(DRM_IOCTL_ARGS)
356 {
357 	DRM_DEBUG("drm_noop\n");
358 	return (0);
359 }
360 
361 /*ARGSUSED*/
362 int
363 drm_version(DRM_IOCTL_ARGS)
364 {
365 	DRM_DEVICE;
366 	drm_version_t version;
367 	size_t len;
368 
369 #ifdef	_MULTI_DATAMODEL
370 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
371 		drm_version_32_t version32;
372 
373 		DRM_COPYFROM_WITH_RETURN(&version32,
374 		    (void *)data, sizeof (drm_version_32_t));
375 		version.name_len = version32.name_len;
376 		version.name = (char *)(uintptr_t)version32.name;
377 		version.date_len = version32.date_len;
378 		version.date = (char *)(uintptr_t)version32.date;
379 		version.desc_len = version32.desc_len;
380 		version.desc = (char *)(uintptr_t)version32.desc;
381 	} else
382 #endif
383 		DRM_COPYFROM_WITH_RETURN(&version, (void *)data,
384 		    sizeof (version));
385 
386 #define	DRM_COPY(name, value)                                         \
387 	len = strlen(value);                                          \
388 	if (len > name##_len) len = name##_len;                       \
389 		name##_len = strlen(value);                                   \
390 	if (len && name) {                                            \
391 		if (DRM_COPY_TO_USER(name, value, len))             \
392 			return (EFAULT);                         \
393 	}
394 
395 	version.version_major = dev->driver->driver_major;
396 	version.version_minor = dev->driver->driver_minor;
397 	version.version_patchlevel = dev->driver->driver_patchlevel;
398 
399 	DRM_COPY(version.name, dev->driver->driver_name);
400 	DRM_COPY(version.date, dev->driver->driver_date);
401 	DRM_COPY(version.desc, dev->driver->driver_desc);
402 
403 #ifdef	_MULTI_DATAMODEL
404 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
405 		drm_version_32_t version32;
406 
407 		version32.version_major = version.version_major;
408 		version32.version_minor = version.version_minor;
409 		version32.version_patchlevel = version.version_patchlevel;
410 		version32.name_len = (uint32_t)version.name_len;
411 		version32.name = (caddr32_t)(uintptr_t)version.name;
412 		version32.date_len = (uint32_t)version.date_len;
413 		version32.date = (caddr32_t)(uintptr_t)version.date;
414 		version32.desc_len = (uint32_t)version.desc_len;
415 		version32.desc = (caddr32_t)(uintptr_t)version.desc;
416 		DRM_COPYTO_WITH_RETURN((void *)data, &version32,
417 		    sizeof (drm_version_32_t));
418 	} else
419 #endif
420 		DRM_COPYTO_WITH_RETURN((void *)data, &version,
421 		    sizeof (version));
422 
423 	return (0);
424 }
425