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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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