drm_stub.c revision 302408
1139735Simp/** 2129198Scognet * \file drm_stub.h 3129198Scognet * Stub support 4129198Scognet * 5129198Scognet * \author Rickard E. (Rik) Faith <faith@valinux.com> 6129198Scognet */ 7129198Scognet 8129198Scognet/* 9129198Scognet * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org 10129198Scognet * 11129198Scognet * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California. 12129198Scognet * All Rights Reserved. 13129198Scognet * 14129198Scognet * Permission is hereby granted, free of charge, to any person obtaining a 15129198Scognet * copy of this software and associated documentation files (the "Software"), 16129198Scognet * to deal in the Software without restriction, including without limitation 17129198Scognet * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18129198Scognet * and/or sell copies of the Software, and to permit persons to whom the 19129198Scognet * Software is furnished to do so, subject to the following conditions: 20129198Scognet * 21129198Scognet * The above copyright notice and this permission notice (including the next 22129198Scognet * paragraph) shall be included in all copies or substantial portions of the 23129198Scognet * Software. 24129198Scognet * 25129198Scognet * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26129198Scognet * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27129198Scognet * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28129198Scognet * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 29129198Scognet * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 30129198Scognet * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31129198Scognet * DEALINGS IN THE SOFTWARE. 32129198Scognet */ 33129198Scognet 34129198Scognet#include <sys/cdefs.h> 35166686Skevlo__FBSDID("$FreeBSD: stable/11/sys/dev/drm2/drm_stub.c 288653 2015-10-04 07:45:36Z adrian $"); 36129198Scognet 37129198Scognet#include <dev/drm2/drmP.h> 38129198Scognet#include <dev/drm2/drm_core.h> 39129198Scognet 40129198Scognet#ifdef DRM_DEBUG_DEFAULT_ON 41129198Scognetunsigned int drm_debug = (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | 42129198Scognet DRM_DEBUGBITS_FAILED_IOCTL); 43129198Scognet#else 44129198Scognetunsigned int drm_debug = 0; /* 1 to enable debug output */ 45129198Scognet#endif 46129198ScognetEXPORT_SYMBOL(drm_debug); 47129198Scognet 48129198Scognetunsigned int drm_notyet = 0; 49140310Scognet 50146597Scognetunsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ 51166063ScognetEXPORT_SYMBOL(drm_vblank_offdelay); 52129198Scognet 53129198Scognetunsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ 54129198ScognetEXPORT_SYMBOL(drm_timestamp_precision); 55129198Scognet 56129198Scognet/* 57129198Scognet * Default to use monotonic timestamps for wait-for-vblank and page-flip 58129198Scognet * complete events. 59129198Scognet */ 60166063Scognetunsigned int drm_timestamp_monotonic = 1; 61129198Scognet 62166063ScognetMODULE_AUTHOR(CORE_AUTHOR); 63166063ScognetMODULE_DESCRIPTION(CORE_DESC); 64166063ScognetMODULE_LICENSE("GPL and additional rights"); 65166063ScognetMODULE_PARM_DESC(debug, "Enable debug output"); 66166063ScognetMODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); 67166063ScognetMODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); 68129198ScognetMODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); 69129198Scognet 70129198Scognetmodule_param_named(debug, drm_debug, int, 0600); 71129198Scognetmodule_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); 72129198Scognetmodule_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 73129198Scognetmodule_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); 74129198Scognet 75129198Scognetstatic struct cdevsw drm_cdevsw = { 76129198Scognet .d_version = D_VERSION, 77129198Scognet .d_open = drm_open, 78129198Scognet .d_read = drm_read, 79129198Scognet .d_ioctl = drm_ioctl, 80129198Scognet .d_poll = drm_poll, 81129198Scognet .d_mmap_single = drm_mmap_single, 82129198Scognet .d_name = "drm", 83129198Scognet .d_flags = D_TRACKCLOSE 84129198Scognet}; 85129198Scognet 86129198Scognetstatic int drm_minor_get_id(struct drm_device *dev, int type) 87129198Scognet{ 88129198Scognet int new_id; 89129198Scognet 90129198Scognet new_id = device_get_unit(dev->dev); 91129198Scognet 92166063Scognet if (new_id >= 64) 93129198Scognet return -EINVAL; 94129198Scognet 95166063Scognet if (type == DRM_MINOR_CONTROL) { 96166063Scognet new_id += 64; 97166063Scognet } else if (type == DRM_MINOR_RENDER) { 98166063Scognet new_id += 128; 99166063Scognet } 100166063Scognet 101166063Scognet return new_id; 102166063Scognet} 103166063Scognet 104166063Scognetstruct drm_master *drm_master_create(struct drm_minor *minor) 105166063Scognet{ 106166063Scognet struct drm_master *master; 107166063Scognet 108166063Scognet master = malloc(sizeof(*master), DRM_MEM_KMS, M_NOWAIT | M_ZERO); 109166063Scognet if (!master) 110166063Scognet return NULL; 111166063Scognet 112166063Scognet refcount_init(&master->refcount, 1); 113166063Scognet mtx_init(&master->lock.spinlock, "drm_master__lock__spinlock", 114166063Scognet NULL, MTX_DEF); 115166063Scognet DRM_INIT_WAITQUEUE(&master->lock.lock_queue); 116166063Scognet drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); 117166063Scognet INIT_LIST_HEAD(&master->magicfree); 118166063Scognet master->minor = minor; 119166063Scognet 120166063Scognet list_add_tail(&master->head, &minor->master_list); 121166063Scognet 122166063Scognet return master; 123166063Scognet} 124166063Scognet 125166063Scognetstruct drm_master *drm_master_get(struct drm_master *master) 126166063Scognet{ 127166063Scognet refcount_acquire(&master->refcount); 128166063Scognet return master; 129166063Scognet} 130166063ScognetEXPORT_SYMBOL(drm_master_get); 131166063Scognet 132166063Scognetstatic void drm_master_destroy(struct drm_master *master) 133135644Scognet{ 134135644Scognet struct drm_magic_entry *pt, *next; 135135644Scognet struct drm_device *dev = master->minor->dev; 136146597Scognet struct drm_map_list *r_list, *list_temp; 137135644Scognet 138135644Scognet list_del(&master->head); 139129198Scognet 140166063Scognet if (dev->driver->master_destroy) 141166063Scognet dev->driver->master_destroy(dev, master); 142166063Scognet 143135644Scognet list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { 144135644Scognet if (r_list->master == master) { 145135644Scognet drm_rmmap_locked(dev, r_list->map); 146156191Scognet r_list = NULL; 147156191Scognet } 148147591Scognet } 149135644Scognet 150166063Scognet if (master->unique) { 151166063Scognet free(master->unique, DRM_MEM_DRIVER); 152166063Scognet master->unique = NULL; 153166063Scognet master->unique_len = 0; 154129198Scognet } 155129198Scognet 156166063Scognet list_for_each_entry_safe(pt, next, &master->magicfree, head) { 157166063Scognet list_del(&pt->head); 158166063Scognet drm_ht_remove_item(&master->magiclist, &pt->hash_item); 159147591Scognet free(pt, DRM_MEM_MAGIC); 160147591Scognet } 161147591Scognet 162146597Scognet drm_ht_remove(&master->magiclist); 163146597Scognet 164146597Scognet free(master, DRM_MEM_KMS); 165146597Scognet} 166146597Scognet 167146597Scognetvoid drm_master_put(struct drm_master **master) 168146597Scognet{ 169166063Scognet if (refcount_release(&(*master)->refcount)) 170166063Scognet drm_master_destroy(*master); 171166063Scognet *master = NULL; 172166063Scognet} 173166063ScognetEXPORT_SYMBOL(drm_master_put); 174166063Scognet 175166063Scognetint drm_setmaster_ioctl(struct drm_device *dev, void *data, 176166063Scognet struct drm_file *file_priv) 177166063Scognet{ 178166063Scognet int ret; 179166063Scognet 180166063Scognet if (file_priv->is_master) 181166063Scognet return 0; 182166063Scognet 183166063Scognet if (file_priv->minor->master && file_priv->minor->master != file_priv->master) 184166063Scognet return -EINVAL; 185166063Scognet 186166063Scognet if (!file_priv->master) 187166063Scognet return -EINVAL; 188166063Scognet 189166063Scognet if (file_priv->minor->master) 190166063Scognet return -EINVAL; 191166063Scognet 192166063Scognet DRM_LOCK(dev); 193166063Scognet file_priv->minor->master = drm_master_get(file_priv->master); 194166063Scognet file_priv->is_master = 1; 195166063Scognet if (dev->driver->master_set) { 196166063Scognet ret = dev->driver->master_set(dev, file_priv, false); 197166063Scognet if (unlikely(ret != 0)) { 198166063Scognet file_priv->is_master = 0; 199166063Scognet drm_master_put(&file_priv->minor->master); 200166063Scognet } 201166063Scognet } 202166063Scognet DRM_UNLOCK(dev); 203166063Scognet 204166063Scognet return 0; 205166063Scognet} 206166063Scognet 207166063Scognetint drm_dropmaster_ioctl(struct drm_device *dev, void *data, 208147591Scognet struct drm_file *file_priv) 209147591Scognet{ 210147591Scognet if (!file_priv->is_master) 211147591Scognet return -EINVAL; 212147591Scognet 213147591Scognet if (!file_priv->minor->master) 214147591Scognet return -EINVAL; 215147591Scognet 216147591Scognet DRM_LOCK(dev); 217147591Scognet if (dev->driver->master_drop) 218147591Scognet dev->driver->master_drop(dev, file_priv, false); 219129198Scognet drm_master_put(&file_priv->minor->master); 220129198Scognet file_priv->is_master = 0; 221129198Scognet DRM_UNLOCK(dev); 222129198Scognet return 0; 223137758Scognet} 224140349Scognet 225137758Scognetint drm_fill_in_dev(struct drm_device *dev, 226137760Scognet struct drm_driver *driver) 227135644Scognet{ 228166063Scognet int retcode, i; 229166063Scognet 230166063Scognet INIT_LIST_HEAD(&dev->filelist); 231166063Scognet INIT_LIST_HEAD(&dev->ctxlist); 232166063Scognet INIT_LIST_HEAD(&dev->maplist); 233166063Scognet INIT_LIST_HEAD(&dev->vblank_event_list); 234166063Scognet 235166063Scognet mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); 236166063Scognet mtx_init(&dev->count_lock, "drmcount", NULL, MTX_DEF); 237166063Scognet mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF); 238166063Scognet sx_init(&dev->dev_struct_lock, "drmslk"); 239166063Scognet mtx_init(&dev->ctxlist_mutex, "drmctxlist", NULL, MTX_DEF); 240166063Scognet mtx_init(&dev->pcir_lock, "drmpcir", NULL, MTX_DEF); 241129198Scognet 242129198Scognet if (drm_ht_create(&dev->map_hash, 12)) { 243129198Scognet return -ENOMEM; 244129198Scognet } 245129198Scognet 246129198Scognet /* the DRM has 6 basic counters */ 247129198Scognet dev->counters = 6; 248129198Scognet dev->types[0] = _DRM_STAT_LOCK; 249129198Scognet dev->types[1] = _DRM_STAT_OPENS; 250129198Scognet dev->types[2] = _DRM_STAT_CLOSES; 251129198Scognet dev->types[3] = _DRM_STAT_IOCTLS; 252129198Scognet dev->types[4] = _DRM_STAT_LOCKS; 253129198Scognet dev->types[5] = _DRM_STAT_UNLOCKS; 254129198Scognet 255129198Scognet /* 256129198Scognet * FIXME Linux<->FreeBSD: this is done in drm_setup() on Linux. 257129198Scognet */ 258129198Scognet for (i = 0; i < ARRAY_SIZE(dev->counts); i++) 259129198Scognet atomic_set(&dev->counts[i], 0); 260129198Scognet 261129198Scognet dev->driver = driver; 262129198Scognet 263129198Scognet retcode = drm_pci_agp_init(dev); 264129198Scognet if (retcode) 265129198Scognet goto error_out_unreg; 266129198Scognet 267129198Scognet 268129198Scognet 269129198Scognet retcode = drm_ctxbitmap_init(dev); 270129198Scognet if (retcode) { 271129198Scognet DRM_ERROR("Cannot allocate memory for context bitmap.\n"); 272129198Scognet goto error_out_unreg; 273129198Scognet } 274129198Scognet 275129198Scognet if (driver->driver_features & DRIVER_GEM) { 276129198Scognet retcode = drm_gem_init(dev); 277129198Scognet if (retcode) { 278129198Scognet DRM_ERROR("Cannot initialize graphics execution " 279129198Scognet "manager (GEM)\n"); 280129198Scognet goto error_out_unreg; 281129198Scognet } 282129198Scognet } 283129198Scognet 284129198Scognet retcode = drm_sysctl_init(dev); 285129198Scognet if (retcode != 0) { 286129198Scognet DRM_ERROR("Failed to create hw.dri sysctl entry: %d\n", 287129198Scognet retcode); 288129198Scognet } 289129198Scognet 290129198Scognet return 0; 291129198Scognet 292129198Scognet error_out_unreg: 293129198Scognet drm_cancel_fill_in_dev(dev); 294129198Scognet return retcode; 295129198Scognet} 296147591ScognetEXPORT_SYMBOL(drm_fill_in_dev); 297146597Scognet 298146597Scognetvoid drm_cancel_fill_in_dev(struct drm_device *dev) 299146597Scognet{ 300146597Scognet struct drm_driver *driver; 301146597Scognet 302147591Scognet driver = dev->driver; 303150860Scognet 304150860Scognet drm_sysctl_cleanup(dev); 305146597Scognet if (driver->driver_features & DRIVER_GEM) 306147591Scognet drm_gem_destroy(dev); 307166063Scognet drm_ctxbitmap_cleanup(dev); 308147591Scognet 309147591Scognet if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && 310147591Scognet dev->agp && dev->agp->agp_mtrr >= 0) { 311147591Scognet int retval; 312166063Scognet retval = drm_mtrr_del(dev->agp->agp_mtrr, 313146597Scognet dev->agp->agp_info.ai_aperture_base, 314146597Scognet dev->agp->agp_info.ai_aperture_size, 315146597Scognet DRM_MTRR_WC); 316147591Scognet DRM_DEBUG("mtrr_del=%d\n", retval); 317146597Scognet } 318146597Scognet free(dev->agp, DRM_MEM_AGPLISTS); 319146597Scognet dev->agp = NULL; 320146597Scognet 321146597Scognet drm_ht_remove(&dev->map_hash); 322146597Scognet 323147591Scognet mtx_destroy(&dev->irq_lock); 324146597Scognet mtx_destroy(&dev->count_lock); 325146597Scognet mtx_destroy(&dev->event_lock); 326146597Scognet sx_destroy(&dev->dev_struct_lock); 327146597Scognet mtx_destroy(&dev->ctxlist_mutex); 328129198Scognet mtx_destroy(&dev->pcir_lock); 329129198Scognet} 330129198Scognet 331135644Scognet/** 332135644Scognet * Get a secondary minor number. 333129198Scognet * 334129198Scognet * \param dev device data structure 335129198Scognet * \param sec-minor structure to hold the assigned minor 336129198Scognet * \return negative number on failure. 337129198Scognet * 338129198Scognet * Search an empty entry and initialize it to the given parameters, and 339129198Scognet * create the proc init entry via proc_init(). This routines assigns 340129198Scognet * minor numbers to secondary heads of multi-headed cards 341129198Scognet */ 342129198Scognetint drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) 343129198Scognet{ 344129198Scognet struct drm_minor *new_minor; 345166063Scognet int ret; 346166063Scognet int minor_id; 347129198Scognet const char *minor_devname; 348129198Scognet 349140313Scognet DRM_DEBUG("\n"); 350143294Smux 351143284Smux minor_id = drm_minor_get_id(dev, type); 352129198Scognet if (minor_id < 0) 353140313Scognet return minor_id; 354129198Scognet 355129198Scognet new_minor = malloc(sizeof(struct drm_minor), DRM_MEM_MINOR, 356129198Scognet M_NOWAIT | M_ZERO); 357129198Scognet if (!new_minor) { 358129198Scognet ret = -ENOMEM; 359129198Scognet goto err_idr; 360129198Scognet } 361129198Scognet 362129198Scognet new_minor->type = type; 363129198Scognet new_minor->dev = dev; 364129198Scognet new_minor->index = minor_id; 365129198Scognet INIT_LIST_HEAD(&new_minor->master_list); 366129198Scognet 367129198Scognet new_minor->buf_sigio = NULL; 368129198Scognet 369135644Scognet switch (type) { 370129198Scognet case DRM_MINOR_CONTROL: 371129198Scognet minor_devname = "dri/controlD%d"; 372129198Scognet break; 373129198Scognet case DRM_MINOR_RENDER: 374129198Scognet minor_devname = "dri/renderD%d"; 375129198Scognet break; 376129198Scognet default: 377129198Scognet minor_devname = "dri/card%d"; 378129198Scognet break; 379129198Scognet } 380129198Scognet 381129198Scognet ret = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &new_minor->device, 382129198Scognet &drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID, 383134934Sscottl DRM_DEV_MODE, minor_devname, minor_id); 384134934Sscottl if (ret) { 385134934Sscottl DRM_ERROR("Failed to create cdev: %d\n", ret); 386134934Sscottl goto err_mem; 387134934Sscottl } 388166063Scognet new_minor->device->si_drv1 = new_minor; 389166063Scognet *minor = new_minor; 390166063Scognet 391129198Scognet DRM_DEBUG("new minor assigned %d\n", minor_id); 392129198Scognet return 0; 393129198Scognet 394129198Scognet 395129198Scogneterr_mem: 396129198Scognet free(new_minor, DRM_MEM_MINOR); 397129198Scogneterr_idr: 398129198Scognet *minor = NULL; 399129198Scognet return ret; 400129198Scognet} 401129198ScognetEXPORT_SYMBOL(drm_get_minor); 402129198Scognet 403166063Scognet/** 404166063Scognet * Put a secondary minor number. 405166063Scognet * 406129198Scognet * \param sec_minor - structure to be released 407166063Scognet * \return always zero 408166063Scognet * 409166063Scognet * Cleans up the proc resources. Not legal for this to be the 410166063Scognet * last minor released. 411166063Scognet * 412166063Scognet */ 413166063Scognetint drm_put_minor(struct drm_minor **minor_p) 414166063Scognet{ 415166063Scognet struct drm_minor *minor = *minor_p; 416166063Scognet 417166063Scognet DRM_DEBUG("release secondary minor %d\n", minor->index); 418166063Scognet 419166063Scognet funsetown(&minor->buf_sigio); 420166063Scognet 421166063Scognet destroy_dev(minor->device); 422166063Scognet 423166063Scognet free(minor, DRM_MEM_MINOR); 424166063Scognet *minor_p = NULL; 425166063Scognet return 0; 426166063Scognet} 427166063ScognetEXPORT_SYMBOL(drm_put_minor); 428166063Scognet 429166063Scognet/** 430170502Scognet * Called via drm_exit() at module unload time or when pci device is 431170502Scognet * unplugged. 432166063Scognet * 433166063Scognet * Cleans up all DRM device, calling drm_lastclose(). 434166063Scognet * 435166063Scognet */ 436143294Smuxvoid drm_put_dev(struct drm_device *dev) 437143284Smux{ 438140313Scognet struct drm_driver *driver; 439129198Scognet struct drm_map_list *r_list, *list_temp; 440129198Scognet 441129198Scognet DRM_DEBUG("\n"); 442129198Scognet 443129198Scognet if (!dev) { 444129198Scognet DRM_ERROR("cleanup called no dev\n"); 445140680Scognet return; 446140313Scognet } 447140680Scognet driver = dev->driver; 448140313Scognet 449129198Scognet drm_lastclose(dev); 450129198Scognet 451129198Scognet if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && 452129198Scognet dev->agp && dev->agp->agp_mtrr >= 0) { 453129198Scognet int retval; 454129198Scognet retval = drm_mtrr_del(dev->agp->agp_mtrr, 455129198Scognet dev->agp->agp_info.ai_aperture_base, 456129198Scognet dev->agp->agp_info.ai_aperture_size, 457129198Scognet DRM_MTRR_WC); 458129198Scognet DRM_DEBUG("mtrr_del=%d\n", retval); 459129198Scognet } 460129198Scognet 461129198Scognet if (drm_core_check_feature(dev, DRIVER_MODESET)) 462129198Scognet drm_mode_group_free(&dev->primary->mode_group); 463129198Scognet 464129198Scognet if (dev->driver->unload) 465129198Scognet dev->driver->unload(dev); 466129198Scognet 467129198Scognet drm_sysctl_cleanup(dev); 468129198Scognet 469129198Scognet if (drm_core_has_AGP(dev) && dev->agp) { 470129198Scognet free(dev->agp, DRM_MEM_AGPLISTS); 471143294Smux dev->agp = NULL; 472140313Scognet } 473129198Scognet 474129198Scognet drm_vblank_cleanup(dev); 475129198Scognet 476166063Scognet list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 477129198Scognet drm_rmmap(dev, r_list->map); 478129198Scognet drm_ht_remove(&dev->map_hash); 479129198Scognet 480129198Scognet drm_ctxbitmap_cleanup(dev); 481129198Scognet 482129198Scognet if (drm_core_check_feature(dev, DRIVER_MODESET)) 483129198Scognet drm_put_minor(&dev->control); 484129198Scognet 485140313Scognet if (driver->driver_features & DRIVER_GEM) 486129198Scognet drm_gem_destroy(dev); 487146597Scognet 488140313Scognet drm_put_minor(&dev->primary); 489143294Smux 490129198Scognet mtx_destroy(&dev->irq_lock); 491140313Scognet mtx_destroy(&dev->count_lock); 492129198Scognet mtx_destroy(&dev->event_lock); 493135644Scognet sx_destroy(&dev->dev_struct_lock); 494161618Scognet mtx_destroy(&dev->ctxlist_mutex); 495129198Scognet mtx_destroy(&dev->pcir_lock); 496129198Scognet 497166063Scognet#ifdef FREEBSD_NOTYET 498166063Scognet list_del(&dev->driver_item); 499166063Scognet#endif /* FREEBSD_NOTYET */ 500166063Scognet} 501166063ScognetEXPORT_SYMBOL(drm_put_dev); 502166063Scognet