drm_stub.c revision 9a298b2acd771d8a5c0004d8f8e4156c65b11f6b
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 <linux/module.h> 35#include <linux/moduleparam.h> 36#include "drmP.h" 37#include "drm_core.h" 38 39unsigned int drm_debug = 0; /* 1 to enable debug output */ 40EXPORT_SYMBOL(drm_debug); 41 42MODULE_AUTHOR(CORE_AUTHOR); 43MODULE_DESCRIPTION(CORE_DESC); 44MODULE_LICENSE("GPL and additional rights"); 45MODULE_PARM_DESC(debug, "Enable debug output"); 46 47module_param_named(debug, drm_debug, int, 0600); 48 49struct idr drm_minors_idr; 50 51struct class *drm_class; 52struct proc_dir_entry *drm_proc_root; 53struct dentry *drm_debugfs_root; 54void drm_ut_debug_printk(unsigned int request_level, 55 const char *prefix, 56 const char *function_name, 57 const char *format, ...) 58{ 59 va_list args; 60 61 if (drm_debug & request_level) { 62 if (function_name) 63 printk(KERN_DEBUG "[%s:%s], ", prefix, function_name); 64 va_start(args, format); 65 vprintk(format, args); 66 va_end(args); 67 } 68} 69EXPORT_SYMBOL(drm_ut_debug_printk); 70static int drm_minor_get_id(struct drm_device *dev, int type) 71{ 72 int new_id; 73 int ret; 74 int base = 0, limit = 63; 75 76 if (type == DRM_MINOR_CONTROL) { 77 base += 64; 78 limit = base + 127; 79 } else if (type == DRM_MINOR_RENDER) { 80 base += 128; 81 limit = base + 255; 82 } 83 84again: 85 if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { 86 DRM_ERROR("Out of memory expanding drawable idr\n"); 87 return -ENOMEM; 88 } 89 mutex_lock(&dev->struct_mutex); 90 ret = idr_get_new_above(&drm_minors_idr, NULL, 91 base, &new_id); 92 mutex_unlock(&dev->struct_mutex); 93 if (ret == -EAGAIN) { 94 goto again; 95 } else if (ret) { 96 return ret; 97 } 98 99 if (new_id >= limit) { 100 idr_remove(&drm_minors_idr, new_id); 101 return -EINVAL; 102 } 103 return new_id; 104} 105 106struct drm_master *drm_master_create(struct drm_minor *minor) 107{ 108 struct drm_master *master; 109 110 master = kzalloc(sizeof(*master), GFP_KERNEL); 111 if (!master) 112 return NULL; 113 114 kref_init(&master->refcount); 115 spin_lock_init(&master->lock.spinlock); 116 init_waitqueue_head(&master->lock.lock_queue); 117 drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); 118 INIT_LIST_HEAD(&master->magicfree); 119 master->minor = minor; 120 121 list_add_tail(&master->head, &minor->master_list); 122 123 return master; 124} 125 126struct drm_master *drm_master_get(struct drm_master *master) 127{ 128 kref_get(&master->refcount); 129 return master; 130} 131 132static void drm_master_destroy(struct kref *kref) 133{ 134 struct drm_master *master = container_of(kref, struct drm_master, refcount); 135 struct drm_magic_entry *pt, *next; 136 struct drm_device *dev = master->minor->dev; 137 struct drm_map_list *r_list, *list_temp; 138 139 list_del(&master->head); 140 141 if (dev->driver->master_destroy) 142 dev->driver->master_destroy(dev, master); 143 144 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { 145 if (r_list->master == master) { 146 drm_rmmap_locked(dev, r_list->map); 147 r_list = NULL; 148 } 149 } 150 151 if (master->unique) { 152 kfree(master->unique); 153 master->unique = NULL; 154 master->unique_len = 0; 155 } 156 157 list_for_each_entry_safe(pt, next, &master->magicfree, head) { 158 list_del(&pt->head); 159 drm_ht_remove_item(&master->magiclist, &pt->hash_item); 160 kfree(pt); 161 } 162 163 drm_ht_remove(&master->magiclist); 164 165 kfree(master); 166} 167 168void drm_master_put(struct drm_master **master) 169{ 170 kref_put(&(*master)->refcount, drm_master_destroy); 171 *master = NULL; 172} 173 174int drm_setmaster_ioctl(struct drm_device *dev, void *data, 175 struct drm_file *file_priv) 176{ 177 if (file_priv->is_master) 178 return 0; 179 180 if (file_priv->minor->master && file_priv->minor->master != file_priv->master) 181 return -EINVAL; 182 183 if (!file_priv->master) 184 return -EINVAL; 185 186 if (!file_priv->minor->master && 187 file_priv->minor->master != file_priv->master) { 188 mutex_lock(&dev->struct_mutex); 189 file_priv->minor->master = drm_master_get(file_priv->master); 190 file_priv->is_master = 1; 191 mutex_unlock(&dev->struct_mutex); 192 } 193 194 return 0; 195} 196 197int drm_dropmaster_ioctl(struct drm_device *dev, void *data, 198 struct drm_file *file_priv) 199{ 200 if (!file_priv->is_master) 201 return -EINVAL; 202 203 if (!file_priv->minor->master) 204 return -EINVAL; 205 206 mutex_lock(&dev->struct_mutex); 207 drm_master_put(&file_priv->minor->master); 208 file_priv->is_master = 0; 209 mutex_unlock(&dev->struct_mutex); 210 return 0; 211} 212 213static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, 214 const struct pci_device_id *ent, 215 struct drm_driver *driver) 216{ 217 int retcode; 218 219 INIT_LIST_HEAD(&dev->filelist); 220 INIT_LIST_HEAD(&dev->ctxlist); 221 INIT_LIST_HEAD(&dev->vmalist); 222 INIT_LIST_HEAD(&dev->maplist); 223 224 spin_lock_init(&dev->count_lock); 225 spin_lock_init(&dev->drw_lock); 226 init_timer(&dev->timer); 227 mutex_init(&dev->struct_mutex); 228 mutex_init(&dev->ctxlist_mutex); 229 230 idr_init(&dev->drw_idr); 231 232 dev->pdev = pdev; 233 dev->pci_device = pdev->device; 234 dev->pci_vendor = pdev->vendor; 235 236#ifdef __alpha__ 237 dev->hose = pdev->sysdata; 238#endif 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 dev->driver = driver; 254 255 if (drm_core_has_AGP(dev)) { 256 if (drm_device_is_agp(dev)) 257 dev->agp = drm_agp_init(dev); 258 if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) 259 && (dev->agp == NULL)) { 260 DRM_ERROR("Cannot initialize the agpgart module.\n"); 261 retcode = -EINVAL; 262 goto error_out_unreg; 263 } 264 if (drm_core_has_MTRR(dev)) { 265 if (dev->agp) 266 dev->agp->agp_mtrr = 267 mtrr_add(dev->agp->agp_info.aper_base, 268 dev->agp->agp_info.aper_size * 269 1024 * 1024, MTRR_TYPE_WRCOMB, 1); 270 } 271 } 272 273 274 retcode = drm_ctxbitmap_init(dev); 275 if (retcode) { 276 DRM_ERROR("Cannot allocate memory for context bitmap.\n"); 277 goto error_out_unreg; 278 } 279 280 if (driver->driver_features & DRIVER_GEM) { 281 retcode = drm_gem_init(dev); 282 if (retcode) { 283 DRM_ERROR("Cannot initialize graphics execution " 284 "manager (GEM)\n"); 285 goto error_out_unreg; 286 } 287 } 288 289 return 0; 290 291 error_out_unreg: 292 drm_lastclose(dev); 293 return retcode; 294} 295 296 297/** 298 * Get a secondary minor number. 299 * 300 * \param dev device data structure 301 * \param sec-minor structure to hold the assigned minor 302 * \return negative number on failure. 303 * 304 * Search an empty entry and initialize it to the given parameters, and 305 * create the proc init entry via proc_init(). This routines assigns 306 * minor numbers to secondary heads of multi-headed cards 307 */ 308static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) 309{ 310 struct drm_minor *new_minor; 311 int ret; 312 int minor_id; 313 314 DRM_DEBUG("\n"); 315 316 minor_id = drm_minor_get_id(dev, type); 317 if (minor_id < 0) 318 return minor_id; 319 320 new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); 321 if (!new_minor) { 322 ret = -ENOMEM; 323 goto err_idr; 324 } 325 326 new_minor->type = type; 327 new_minor->device = MKDEV(DRM_MAJOR, minor_id); 328 new_minor->dev = dev; 329 new_minor->index = minor_id; 330 INIT_LIST_HEAD(&new_minor->master_list); 331 332 idr_replace(&drm_minors_idr, new_minor, minor_id); 333 334 if (type == DRM_MINOR_LEGACY) { 335 ret = drm_proc_init(new_minor, minor_id, drm_proc_root); 336 if (ret) { 337 DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); 338 goto err_mem; 339 } 340 } else 341 new_minor->proc_root = NULL; 342 343#if defined(CONFIG_DEBUG_FS) 344 ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); 345 if (ret) { 346 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); 347 goto err_g2; 348 } 349#endif 350 351 ret = drm_sysfs_device_add(new_minor); 352 if (ret) { 353 printk(KERN_ERR 354 "DRM: Error sysfs_device_add.\n"); 355 goto err_g2; 356 } 357 *minor = new_minor; 358 359 DRM_DEBUG("new minor assigned %d\n", minor_id); 360 return 0; 361 362 363err_g2: 364 if (new_minor->type == DRM_MINOR_LEGACY) 365 drm_proc_cleanup(new_minor, drm_proc_root); 366err_mem: 367 kfree(new_minor); 368err_idr: 369 idr_remove(&drm_minors_idr, minor_id); 370 *minor = NULL; 371 return ret; 372} 373 374/** 375 * Register. 376 * 377 * \param pdev - PCI device structure 378 * \param ent entry from the PCI ID table with device type flags 379 * \return zero on success or a negative number on failure. 380 * 381 * Attempt to gets inter module "drm" information. If we are first 382 * then register the character device and inter module information. 383 * Try and register, if we fail to register, backout previous work. 384 */ 385int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, 386 struct drm_driver *driver) 387{ 388 struct drm_device *dev; 389 int ret; 390 391 DRM_DEBUG("\n"); 392 393 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 394 if (!dev) 395 return -ENOMEM; 396 397 ret = pci_enable_device(pdev); 398 if (ret) 399 goto err_g1; 400 401 pci_set_master(pdev); 402 if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { 403 printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); 404 goto err_g2; 405 } 406 407 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 408 pci_set_drvdata(pdev, dev); 409 ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); 410 if (ret) 411 goto err_g2; 412 } 413 414 if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) 415 goto err_g3; 416 417 if (dev->driver->load) { 418 ret = dev->driver->load(dev, ent->driver_data); 419 if (ret) 420 goto err_g4; 421 } 422 423 /* setup the grouping for the legacy output */ 424 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 425 ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); 426 if (ret) 427 goto err_g4; 428 } 429 430 list_add_tail(&dev->driver_item, &driver->device_list); 431 432 DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", 433 driver->name, driver->major, driver->minor, driver->patchlevel, 434 driver->date, pci_name(pdev), dev->primary->index); 435 436 return 0; 437 438err_g4: 439 drm_put_minor(&dev->primary); 440err_g3: 441 if (drm_core_check_feature(dev, DRIVER_MODESET)) 442 drm_put_minor(&dev->control); 443err_g2: 444 pci_disable_device(pdev); 445err_g1: 446 kfree(dev); 447 return ret; 448} 449EXPORT_SYMBOL(drm_get_dev); 450 451/** 452 * Put a secondary minor number. 453 * 454 * \param sec_minor - structure to be released 455 * \return always zero 456 * 457 * Cleans up the proc resources. Not legal for this to be the 458 * last minor released. 459 * 460 */ 461int drm_put_minor(struct drm_minor **minor_p) 462{ 463 struct drm_minor *minor = *minor_p; 464 465 DRM_DEBUG("release secondary minor %d\n", minor->index); 466 467 if (minor->type == DRM_MINOR_LEGACY) 468 drm_proc_cleanup(minor, drm_proc_root); 469#if defined(CONFIG_DEBUG_FS) 470 drm_debugfs_cleanup(minor); 471#endif 472 473 drm_sysfs_device_remove(minor); 474 475 idr_remove(&drm_minors_idr, minor->index); 476 477 kfree(minor); 478 *minor_p = NULL; 479 return 0; 480} 481 482/** 483 * Called via drm_exit() at module unload time or when pci device is 484 * unplugged. 485 * 486 * Cleans up all DRM device, calling drm_lastclose(). 487 * 488 * \sa drm_init 489 */ 490void drm_put_dev(struct drm_device *dev) 491{ 492 struct drm_driver *driver = dev->driver; 493 struct drm_map_list *r_list, *list_temp; 494 495 DRM_DEBUG("\n"); 496 497 if (!dev) { 498 DRM_ERROR("cleanup called no dev\n"); 499 return; 500 } 501 502 drm_vblank_cleanup(dev); 503 504 drm_lastclose(dev); 505 506 if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && 507 dev->agp && dev->agp->agp_mtrr >= 0) { 508 int retval; 509 retval = mtrr_del(dev->agp->agp_mtrr, 510 dev->agp->agp_info.aper_base, 511 dev->agp->agp_info.aper_size * 1024 * 1024); 512 DRM_DEBUG("mtrr_del=%d\n", retval); 513 } 514 515 if (dev->driver->unload) 516 dev->driver->unload(dev); 517 518 if (drm_core_has_AGP(dev) && dev->agp) { 519 kfree(dev->agp); 520 dev->agp = NULL; 521 } 522 523 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 524 drm_rmmap(dev, r_list->map); 525 drm_ht_remove(&dev->map_hash); 526 527 drm_ctxbitmap_cleanup(dev); 528 529 if (drm_core_check_feature(dev, DRIVER_MODESET)) 530 drm_put_minor(&dev->control); 531 532 if (driver->driver_features & DRIVER_GEM) 533 drm_gem_destroy(dev); 534 535 drm_put_minor(&dev->primary); 536 537 if (dev->devname) { 538 kfree(dev->devname); 539 dev->devname = NULL; 540 } 541 kfree(dev); 542} 543EXPORT_SYMBOL(drm_put_dev); 544