1 /**
2 * \file drm_stub.h
3 * Stub support
4 *
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 */
7
8 /*
9 * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
10 *
11 * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
23 * Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
33
34 #include <sys/cdefs.h>
35 #include <dev/drm2/drmP.h>
36 #include <dev/drm2/drm_core.h>
37
38 #ifdef DRM_DEBUG_DEFAULT_ON
39 unsigned int drm_debug = (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS |
40 DRM_DEBUGBITS_FAILED_IOCTL);
41 #else
42 unsigned int drm_debug = 0; /* 1 to enable debug output */
43 #endif
44 EXPORT_SYMBOL(drm_debug);
45
46 unsigned int drm_notyet = 0;
47
48 unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
49 EXPORT_SYMBOL(drm_vblank_offdelay);
50
51 unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
52 EXPORT_SYMBOL(drm_timestamp_precision);
53
54 /*
55 * Default to use monotonic timestamps for wait-for-vblank and page-flip
56 * complete events.
57 */
58 unsigned int drm_timestamp_monotonic = 1;
59
60 MODULE_AUTHOR(CORE_AUTHOR);
61 MODULE_DESCRIPTION(CORE_DESC);
62 MODULE_LICENSE("GPL and additional rights");
63 MODULE_PARM_DESC(debug, "Enable debug output");
64 MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
65 MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
66 MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
67
68 module_param_named(debug, drm_debug, int, 0600);
69 module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
70 module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
71 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
72
73 static struct cdevsw drm_cdevsw = {
74 .d_version = D_VERSION,
75 .d_open = drm_open,
76 .d_read = drm_read,
77 .d_ioctl = drm_ioctl,
78 .d_poll = drm_poll,
79 .d_mmap_single = drm_mmap_single,
80 .d_name = "drm",
81 .d_flags = D_TRACKCLOSE
82 };
83
drm_minor_get_id(struct drm_device * dev,int type)84 static int drm_minor_get_id(struct drm_device *dev, int type)
85 {
86 int new_id;
87
88 new_id = device_get_unit(dev->dev);
89
90 if (new_id >= 64)
91 return -EINVAL;
92
93 if (type == DRM_MINOR_CONTROL) {
94 new_id += 64;
95 } else if (type == DRM_MINOR_RENDER) {
96 new_id += 128;
97 }
98
99 return new_id;
100 }
101
drm_master_create(struct drm_minor * minor)102 struct drm_master *drm_master_create(struct drm_minor *minor)
103 {
104 struct drm_master *master;
105
106 master = malloc(sizeof(*master), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
107 if (!master)
108 return NULL;
109
110 refcount_init(&master->refcount, 1);
111 mtx_init(&master->lock.spinlock, "drm_master__lock__spinlock",
112 NULL, MTX_DEF);
113 DRM_INIT_WAITQUEUE(&master->lock.lock_queue);
114 drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
115 INIT_LIST_HEAD(&master->magicfree);
116 master->minor = minor;
117
118 list_add_tail(&master->head, &minor->master_list);
119
120 return master;
121 }
122
drm_master_get(struct drm_master * master)123 struct drm_master *drm_master_get(struct drm_master *master)
124 {
125 refcount_acquire(&master->refcount);
126 return master;
127 }
128 EXPORT_SYMBOL(drm_master_get);
129
drm_master_destroy(struct drm_master * master)130 static void drm_master_destroy(struct drm_master *master)
131 {
132 struct drm_magic_entry *pt, *next;
133 struct drm_device *dev = master->minor->dev;
134 struct drm_map_list *r_list, *list_temp;
135
136 list_del(&master->head);
137
138 if (dev->driver->master_destroy)
139 dev->driver->master_destroy(dev, master);
140
141 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
142 if (r_list->master == master) {
143 drm_rmmap_locked(dev, r_list->map);
144 r_list = NULL;
145 }
146 }
147
148 if (master->unique) {
149 free(master->unique, DRM_MEM_DRIVER);
150 master->unique = NULL;
151 master->unique_len = 0;
152 }
153
154 list_for_each_entry_safe(pt, next, &master->magicfree, head) {
155 list_del(&pt->head);
156 drm_ht_remove_item(&master->magiclist, &pt->hash_item);
157 free(pt, DRM_MEM_MAGIC);
158 }
159
160 drm_ht_remove(&master->magiclist);
161
162 free(master, DRM_MEM_KMS);
163 }
164
drm_master_put(struct drm_master ** master)165 void drm_master_put(struct drm_master **master)
166 {
167 if (refcount_release(&(*master)->refcount))
168 drm_master_destroy(*master);
169 *master = NULL;
170 }
171 EXPORT_SYMBOL(drm_master_put);
172
drm_setmaster_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)173 int drm_setmaster_ioctl(struct drm_device *dev, void *data,
174 struct drm_file *file_priv)
175 {
176 int ret;
177
178 if (file_priv->is_master)
179 return 0;
180
181 if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
182 return -EINVAL;
183
184 if (!file_priv->master)
185 return -EINVAL;
186
187 if (file_priv->minor->master)
188 return -EINVAL;
189
190 DRM_LOCK(dev);
191 file_priv->minor->master = drm_master_get(file_priv->master);
192 file_priv->is_master = 1;
193 if (dev->driver->master_set) {
194 ret = dev->driver->master_set(dev, file_priv, false);
195 if (unlikely(ret != 0)) {
196 file_priv->is_master = 0;
197 drm_master_put(&file_priv->minor->master);
198 }
199 }
200 DRM_UNLOCK(dev);
201
202 return 0;
203 }
204
drm_dropmaster_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)205 int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
206 struct drm_file *file_priv)
207 {
208 if (!file_priv->is_master)
209 return -EINVAL;
210
211 if (!file_priv->minor->master)
212 return -EINVAL;
213
214 DRM_LOCK(dev);
215 if (dev->driver->master_drop)
216 dev->driver->master_drop(dev, file_priv, false);
217 drm_master_put(&file_priv->minor->master);
218 file_priv->is_master = 0;
219 DRM_UNLOCK(dev);
220 return 0;
221 }
222
drm_fill_in_dev(struct drm_device * dev,struct drm_driver * driver)223 int drm_fill_in_dev(struct drm_device *dev,
224 struct drm_driver *driver)
225 {
226 int retcode, i;
227
228 INIT_LIST_HEAD(&dev->filelist);
229 INIT_LIST_HEAD(&dev->ctxlist);
230 INIT_LIST_HEAD(&dev->maplist);
231 INIT_LIST_HEAD(&dev->vblank_event_list);
232
233 mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
234 mtx_init(&dev->count_lock, "drmcount", NULL, MTX_DEF);
235 mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF);
236 sx_init(&dev->dev_struct_lock, "drmslk");
237 mtx_init(&dev->ctxlist_mutex, "drmctxlist", NULL, MTX_DEF);
238 mtx_init(&dev->pcir_lock, "drmpcir", NULL, MTX_DEF);
239
240 if (drm_ht_create(&dev->map_hash, 12)) {
241 return -ENOMEM;
242 }
243
244 /* the DRM has 6 basic counters */
245 dev->counters = 6;
246 dev->types[0] = _DRM_STAT_LOCK;
247 dev->types[1] = _DRM_STAT_OPENS;
248 dev->types[2] = _DRM_STAT_CLOSES;
249 dev->types[3] = _DRM_STAT_IOCTLS;
250 dev->types[4] = _DRM_STAT_LOCKS;
251 dev->types[5] = _DRM_STAT_UNLOCKS;
252
253 /*
254 * FIXME Linux<->FreeBSD: this is done in drm_setup() on Linux.
255 */
256 for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
257 atomic_set(&dev->counts[i], 0);
258
259 dev->driver = driver;
260
261 retcode = drm_pci_agp_init(dev);
262 if (retcode)
263 goto error_out_unreg;
264
265
266
267 retcode = drm_ctxbitmap_init(dev);
268 if (retcode) {
269 DRM_ERROR("Cannot allocate memory for context bitmap.\n");
270 goto error_out_unreg;
271 }
272
273 if (driver->driver_features & DRIVER_GEM) {
274 retcode = drm_gem_init(dev);
275 if (retcode) {
276 DRM_ERROR("Cannot initialize graphics execution "
277 "manager (GEM)\n");
278 goto error_out_unreg;
279 }
280 }
281
282 retcode = drm_sysctl_init(dev);
283 if (retcode != 0) {
284 DRM_ERROR("Failed to create hw.dri sysctl entry: %d\n",
285 retcode);
286 }
287
288 return 0;
289
290 error_out_unreg:
291 drm_cancel_fill_in_dev(dev);
292 return retcode;
293 }
294 EXPORT_SYMBOL(drm_fill_in_dev);
295
drm_cancel_fill_in_dev(struct drm_device * dev)296 void drm_cancel_fill_in_dev(struct drm_device *dev)
297 {
298 struct drm_driver *driver;
299
300 driver = dev->driver;
301
302 drm_sysctl_cleanup(dev);
303 if (driver->driver_features & DRIVER_GEM)
304 drm_gem_destroy(dev);
305 drm_ctxbitmap_cleanup(dev);
306
307 if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
308 dev->agp && dev->agp->agp_mtrr >= 0) {
309 int retval;
310 retval = drm_mtrr_del(dev->agp->agp_mtrr,
311 dev->agp->agp_info.ai_aperture_base,
312 dev->agp->agp_info.ai_aperture_size,
313 DRM_MTRR_WC);
314 DRM_DEBUG("mtrr_del=%d\n", retval);
315 }
316 free(dev->agp, DRM_MEM_AGPLISTS);
317 dev->agp = NULL;
318
319 drm_ht_remove(&dev->map_hash);
320
321 mtx_destroy(&dev->irq_lock);
322 mtx_destroy(&dev->count_lock);
323 mtx_destroy(&dev->event_lock);
324 sx_destroy(&dev->dev_struct_lock);
325 mtx_destroy(&dev->ctxlist_mutex);
326 mtx_destroy(&dev->pcir_lock);
327 }
328
329 /**
330 * Get a secondary minor number.
331 *
332 * \param dev device data structure
333 * \param sec-minor structure to hold the assigned minor
334 * \return negative number on failure.
335 *
336 * Search an empty entry and initialize it to the given parameters, and
337 * create the proc init entry via proc_init(). This routines assigns
338 * minor numbers to secondary heads of multi-headed cards
339 */
drm_get_minor(struct drm_device * dev,struct drm_minor ** minor,int type)340 int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
341 {
342 struct drm_minor *new_minor;
343 int ret;
344 int minor_id;
345 const char *minor_devname;
346
347 DRM_DEBUG("\n");
348
349 minor_id = drm_minor_get_id(dev, type);
350 if (minor_id < 0)
351 return minor_id;
352
353 new_minor = malloc(sizeof(struct drm_minor), DRM_MEM_MINOR,
354 M_NOWAIT | M_ZERO);
355 if (!new_minor) {
356 ret = -ENOMEM;
357 goto err_idr;
358 }
359
360 new_minor->type = type;
361 new_minor->dev = dev;
362 new_minor->index = minor_id;
363 INIT_LIST_HEAD(&new_minor->master_list);
364
365 new_minor->buf_sigio = NULL;
366
367 switch (type) {
368 case DRM_MINOR_CONTROL:
369 minor_devname = "dri/controlD%d";
370 break;
371 case DRM_MINOR_RENDER:
372 minor_devname = "dri/renderD%d";
373 break;
374 default:
375 minor_devname = "dri/card%d";
376 break;
377 }
378
379 ret = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &new_minor->device,
380 &drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID,
381 DRM_DEV_MODE, minor_devname, minor_id);
382 if (ret) {
383 DRM_ERROR("Failed to create cdev: %d\n", ret);
384 goto err_mem;
385 }
386 new_minor->device->si_drv1 = new_minor;
387 *minor = new_minor;
388
389 DRM_DEBUG("new minor assigned %d\n", minor_id);
390 return 0;
391
392
393 err_mem:
394 free(new_minor, DRM_MEM_MINOR);
395 err_idr:
396 *minor = NULL;
397 return ret;
398 }
399 EXPORT_SYMBOL(drm_get_minor);
400
401 /**
402 * Put a secondary minor number.
403 *
404 * \param sec_minor - structure to be released
405 * \return always zero
406 *
407 * Cleans up the proc resources. Not legal for this to be the
408 * last minor released.
409 *
410 */
drm_put_minor(struct drm_minor ** minor_p)411 int drm_put_minor(struct drm_minor **minor_p)
412 {
413 struct drm_minor *minor = *minor_p;
414
415 DRM_DEBUG("release secondary minor %d\n", minor->index);
416
417 funsetown(&minor->buf_sigio);
418
419 destroy_dev(minor->device);
420
421 free(minor, DRM_MEM_MINOR);
422 *minor_p = NULL;
423 return 0;
424 }
425 EXPORT_SYMBOL(drm_put_minor);
426
427 /**
428 * Called via drm_exit() at module unload time or when pci device is
429 * unplugged.
430 *
431 * Cleans up all DRM device, calling drm_lastclose().
432 *
433 */
drm_put_dev(struct drm_device * dev)434 void drm_put_dev(struct drm_device *dev)
435 {
436 struct drm_driver *driver;
437 struct drm_map_list *r_list, *list_temp;
438
439 DRM_DEBUG("\n");
440
441 if (!dev) {
442 DRM_ERROR("cleanup called no dev\n");
443 return;
444 }
445 driver = dev->driver;
446
447 drm_lastclose(dev);
448
449 if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
450 dev->agp && dev->agp->agp_mtrr >= 0) {
451 int retval;
452 retval = drm_mtrr_del(dev->agp->agp_mtrr,
453 dev->agp->agp_info.ai_aperture_base,
454 dev->agp->agp_info.ai_aperture_size,
455 DRM_MTRR_WC);
456 DRM_DEBUG("mtrr_del=%d\n", retval);
457 }
458
459 if (drm_core_check_feature(dev, DRIVER_MODESET))
460 drm_mode_group_free(&dev->primary->mode_group);
461
462 if (dev->driver->unload)
463 dev->driver->unload(dev);
464
465 drm_sysctl_cleanup(dev);
466
467 if (drm_core_has_AGP(dev) && dev->agp) {
468 free(dev->agp, DRM_MEM_AGPLISTS);
469 dev->agp = NULL;
470 }
471
472 drm_vblank_cleanup(dev);
473
474 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
475 drm_rmmap(dev, r_list->map);
476 drm_ht_remove(&dev->map_hash);
477
478 drm_ctxbitmap_cleanup(dev);
479
480 if (drm_core_check_feature(dev, DRIVER_MODESET))
481 drm_put_minor(&dev->control);
482
483 if (driver->driver_features & DRIVER_GEM)
484 drm_gem_destroy(dev);
485
486 drm_put_minor(&dev->primary);
487
488 mtx_destroy(&dev->irq_lock);
489 mtx_destroy(&dev->count_lock);
490 mtx_destroy(&dev->event_lock);
491 sx_destroy(&dev->dev_struct_lock);
492 mtx_destroy(&dev->ctxlist_mutex);
493 mtx_destroy(&dev->pcir_lock);
494
495 #ifdef FREEBSD_NOTYET
496 list_del(&dev->driver_item);
497 #endif /* FREEBSD_NOTYET */
498 }
499 EXPORT_SYMBOL(drm_put_dev);
500