diff options
Diffstat (limited to 'drivers/gpu/drm/drm_stub.c')
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 362 |
1 files changed, 242 insertions, 120 deletions
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 39d864576be4..c200136a5d8e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
@@ -254,81 +254,21 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | |||
254 | return 0; | 254 | return 0; |
255 | } | 255 | } |
256 | 256 | ||
257 | int drm_fill_in_dev(struct drm_device *dev, | ||
258 | const struct pci_device_id *ent, | ||
259 | struct drm_driver *driver) | ||
260 | { | ||
261 | int retcode; | ||
262 | |||
263 | INIT_LIST_HEAD(&dev->filelist); | ||
264 | INIT_LIST_HEAD(&dev->ctxlist); | ||
265 | INIT_LIST_HEAD(&dev->vmalist); | ||
266 | INIT_LIST_HEAD(&dev->maplist); | ||
267 | INIT_LIST_HEAD(&dev->vblank_event_list); | ||
268 | |||
269 | spin_lock_init(&dev->count_lock); | ||
270 | spin_lock_init(&dev->event_lock); | ||
271 | mutex_init(&dev->struct_mutex); | ||
272 | mutex_init(&dev->ctxlist_mutex); | ||
273 | |||
274 | if (drm_ht_create(&dev->map_hash, 12)) { | ||
275 | return -ENOMEM; | ||
276 | } | ||
277 | |||
278 | /* the DRM has 6 basic counters */ | ||
279 | dev->counters = 6; | ||
280 | dev->types[0] = _DRM_STAT_LOCK; | ||
281 | dev->types[1] = _DRM_STAT_OPENS; | ||
282 | dev->types[2] = _DRM_STAT_CLOSES; | ||
283 | dev->types[3] = _DRM_STAT_IOCTLS; | ||
284 | dev->types[4] = _DRM_STAT_LOCKS; | ||
285 | dev->types[5] = _DRM_STAT_UNLOCKS; | ||
286 | |||
287 | dev->driver = driver; | ||
288 | |||
289 | if (dev->driver->bus->agp_init) { | ||
290 | retcode = dev->driver->bus->agp_init(dev); | ||
291 | if (retcode) | ||
292 | goto error_out_unreg; | ||
293 | } | ||
294 | |||
295 | |||
296 | |||
297 | retcode = drm_ctxbitmap_init(dev); | ||
298 | if (retcode) { | ||
299 | DRM_ERROR("Cannot allocate memory for context bitmap.\n"); | ||
300 | goto error_out_unreg; | ||
301 | } | ||
302 | |||
303 | if (driver->driver_features & DRIVER_GEM) { | ||
304 | retcode = drm_gem_init(dev); | ||
305 | if (retcode) { | ||
306 | DRM_ERROR("Cannot initialize graphics execution " | ||
307 | "manager (GEM)\n"); | ||
308 | goto error_out_unreg; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | error_out_unreg: | ||
315 | drm_lastclose(dev); | ||
316 | return retcode; | ||
317 | } | ||
318 | EXPORT_SYMBOL(drm_fill_in_dev); | ||
319 | |||
320 | |||
321 | /** | 257 | /** |
322 | * Get a secondary minor number. | 258 | * drm_get_minor - Allocate and register new DRM minor |
259 | * @dev: DRM device | ||
260 | * @minor: Pointer to where new minor is stored | ||
261 | * @type: Type of minor | ||
323 | * | 262 | * |
324 | * \param dev device data structure | 263 | * Allocate a new minor of the given type and register it. A pointer to the new |
325 | * \param sec-minor structure to hold the assigned minor | 264 | * minor is returned in @minor. |
326 | * \return negative number on failure. | 265 | * Caller must hold the global DRM mutex. |
327 | * | 266 | * |
328 | * Search an empty entry and initialize it to the given parameters. This | 267 | * RETURNS: |
329 | * routines assigns minor numbers to secondary heads of multi-headed cards | 268 | * 0 on success, negative error code on failure. |
330 | */ | 269 | */ |
331 | int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) | 270 | static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, |
271 | int type) | ||
332 | { | 272 | { |
333 | struct drm_minor *new_minor; | 273 | struct drm_minor *new_minor; |
334 | int ret; | 274 | int ret; |
@@ -385,37 +325,48 @@ err_idr: | |||
385 | *minor = NULL; | 325 | *minor = NULL; |
386 | return ret; | 326 | return ret; |
387 | } | 327 | } |
388 | EXPORT_SYMBOL(drm_get_minor); | ||
389 | 328 | ||
390 | /** | 329 | /** |
391 | * Put a secondary minor number. | 330 | * drm_unplug_minor - Unplug DRM minor |
331 | * @minor: Minor to unplug | ||
392 | * | 332 | * |
393 | * \param sec_minor - structure to be released | 333 | * Unplugs the given DRM minor but keeps the object. So after this returns, |
394 | * \return always zero | 334 | * minor->dev is still valid so existing open-files can still access it to get |
335 | * device information from their drm_file ojects. | ||
336 | * If the minor is already unplugged or if @minor is NULL, nothing is done. | ||
337 | * The global DRM mutex must be held by the caller. | ||
395 | */ | 338 | */ |
396 | int drm_put_minor(struct drm_minor **minor_p) | 339 | static void drm_unplug_minor(struct drm_minor *minor) |
397 | { | 340 | { |
398 | struct drm_minor *minor = *minor_p; | 341 | if (!minor || !device_is_registered(minor->kdev)) |
399 | 342 | return; | |
400 | DRM_DEBUG("release secondary minor %d\n", minor->index); | ||
401 | 343 | ||
402 | #if defined(CONFIG_DEBUG_FS) | 344 | #if defined(CONFIG_DEBUG_FS) |
403 | drm_debugfs_cleanup(minor); | 345 | drm_debugfs_cleanup(minor); |
404 | #endif | 346 | #endif |
405 | 347 | ||
406 | drm_sysfs_device_remove(minor); | 348 | drm_sysfs_device_remove(minor); |
407 | |||
408 | idr_remove(&drm_minors_idr, minor->index); | 349 | idr_remove(&drm_minors_idr, minor->index); |
409 | |||
410 | kfree(minor); | ||
411 | *minor_p = NULL; | ||
412 | return 0; | ||
413 | } | 350 | } |
414 | EXPORT_SYMBOL(drm_put_minor); | ||
415 | 351 | ||
416 | static void drm_unplug_minor(struct drm_minor *minor) | 352 | /** |
353 | * drm_put_minor - Destroy DRM minor | ||
354 | * @minor: Minor to destroy | ||
355 | * | ||
356 | * This calls drm_unplug_minor() on the given minor and then frees it. Nothing | ||
357 | * is done if @minor is NULL. It is fine to call this on already unplugged | ||
358 | * minors. | ||
359 | * The global DRM mutex must be held by the caller. | ||
360 | */ | ||
361 | static void drm_put_minor(struct drm_minor *minor) | ||
417 | { | 362 | { |
418 | drm_sysfs_device_remove(minor); | 363 | if (!minor) |
364 | return; | ||
365 | |||
366 | DRM_DEBUG("release secondary minor %d\n", minor->index); | ||
367 | |||
368 | drm_unplug_minor(minor); | ||
369 | kfree(minor); | ||
419 | } | 370 | } |
420 | 371 | ||
421 | /** | 372 | /** |
@@ -427,66 +378,237 @@ static void drm_unplug_minor(struct drm_minor *minor) | |||
427 | */ | 378 | */ |
428 | void drm_put_dev(struct drm_device *dev) | 379 | void drm_put_dev(struct drm_device *dev) |
429 | { | 380 | { |
430 | struct drm_driver *driver; | ||
431 | struct drm_map_list *r_list, *list_temp; | ||
432 | |||
433 | DRM_DEBUG("\n"); | 381 | DRM_DEBUG("\n"); |
434 | 382 | ||
435 | if (!dev) { | 383 | if (!dev) { |
436 | DRM_ERROR("cleanup called no dev\n"); | 384 | DRM_ERROR("cleanup called no dev\n"); |
437 | return; | 385 | return; |
438 | } | 386 | } |
439 | driver = dev->driver; | ||
440 | 387 | ||
441 | drm_lastclose(dev); | 388 | drm_dev_unregister(dev); |
389 | drm_dev_free(dev); | ||
390 | } | ||
391 | EXPORT_SYMBOL(drm_put_dev); | ||
442 | 392 | ||
443 | if (dev->driver->unload) | 393 | void drm_unplug_dev(struct drm_device *dev) |
444 | dev->driver->unload(dev); | 394 | { |
395 | /* for a USB device */ | ||
396 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
397 | drm_unplug_minor(dev->control); | ||
398 | if (dev->render) | ||
399 | drm_unplug_minor(dev->render); | ||
400 | drm_unplug_minor(dev->primary); | ||
445 | 401 | ||
446 | if (dev->driver->bus->agp_destroy) | 402 | mutex_lock(&drm_global_mutex); |
447 | dev->driver->bus->agp_destroy(dev); | ||
448 | 403 | ||
449 | drm_vblank_cleanup(dev); | 404 | drm_device_set_unplugged(dev); |
450 | 405 | ||
451 | list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) | 406 | if (dev->open_count == 0) { |
452 | drm_rmmap(dev, r_list->map); | 407 | drm_put_dev(dev); |
453 | drm_ht_remove(&dev->map_hash); | 408 | } |
409 | mutex_unlock(&drm_global_mutex); | ||
410 | } | ||
411 | EXPORT_SYMBOL(drm_unplug_dev); | ||
454 | 412 | ||
455 | drm_ctxbitmap_cleanup(dev); | 413 | /** |
414 | * drm_dev_alloc - Allocate new drm device | ||
415 | * @driver: DRM driver to allocate device for | ||
416 | * @parent: Parent device object | ||
417 | * | ||
418 | * Allocate and initialize a new DRM device. No device registration is done. | ||
419 | * Call drm_dev_register() to advertice the device to user space and register it | ||
420 | * with other core subsystems. | ||
421 | * | ||
422 | * RETURNS: | ||
423 | * Pointer to new DRM device, or NULL if out of memory. | ||
424 | */ | ||
425 | struct drm_device *drm_dev_alloc(struct drm_driver *driver, | ||
426 | struct device *parent) | ||
427 | { | ||
428 | struct drm_device *dev; | ||
429 | int ret; | ||
456 | 430 | ||
457 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | 431 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
458 | drm_put_minor(&dev->control); | 432 | if (!dev) |
433 | return NULL; | ||
459 | 434 | ||
460 | if (dev->render) | 435 | dev->dev = parent; |
461 | drm_put_minor(&dev->render); | 436 | dev->driver = driver; |
462 | 437 | ||
463 | if (driver->driver_features & DRIVER_GEM) | 438 | INIT_LIST_HEAD(&dev->filelist); |
439 | INIT_LIST_HEAD(&dev->ctxlist); | ||
440 | INIT_LIST_HEAD(&dev->vmalist); | ||
441 | INIT_LIST_HEAD(&dev->maplist); | ||
442 | INIT_LIST_HEAD(&dev->vblank_event_list); | ||
443 | |||
444 | spin_lock_init(&dev->count_lock); | ||
445 | spin_lock_init(&dev->event_lock); | ||
446 | mutex_init(&dev->struct_mutex); | ||
447 | mutex_init(&dev->ctxlist_mutex); | ||
448 | |||
449 | if (drm_ht_create(&dev->map_hash, 12)) | ||
450 | goto err_free; | ||
451 | |||
452 | ret = drm_ctxbitmap_init(dev); | ||
453 | if (ret) { | ||
454 | DRM_ERROR("Cannot allocate memory for context bitmap.\n"); | ||
455 | goto err_ht; | ||
456 | } | ||
457 | |||
458 | if (driver->driver_features & DRIVER_GEM) { | ||
459 | ret = drm_gem_init(dev); | ||
460 | if (ret) { | ||
461 | DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n"); | ||
462 | goto err_ctxbitmap; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | return dev; | ||
467 | |||
468 | err_ctxbitmap: | ||
469 | drm_ctxbitmap_cleanup(dev); | ||
470 | err_ht: | ||
471 | drm_ht_remove(&dev->map_hash); | ||
472 | err_free: | ||
473 | kfree(dev); | ||
474 | return NULL; | ||
475 | } | ||
476 | EXPORT_SYMBOL(drm_dev_alloc); | ||
477 | |||
478 | /** | ||
479 | * drm_dev_free - Free DRM device | ||
480 | * @dev: DRM device to free | ||
481 | * | ||
482 | * Free a DRM device that has previously been allocated via drm_dev_alloc(). | ||
483 | * You must not use kfree() instead or you will leak memory. | ||
484 | * | ||
485 | * This must not be called once the device got registered. Use drm_put_dev() | ||
486 | * instead, which then calls drm_dev_free(). | ||
487 | */ | ||
488 | void drm_dev_free(struct drm_device *dev) | ||
489 | { | ||
490 | drm_put_minor(dev->control); | ||
491 | drm_put_minor(dev->render); | ||
492 | drm_put_minor(dev->primary); | ||
493 | |||
494 | if (dev->driver->driver_features & DRIVER_GEM) | ||
464 | drm_gem_destroy(dev); | 495 | drm_gem_destroy(dev); |
465 | 496 | ||
466 | drm_put_minor(&dev->primary); | 497 | drm_ctxbitmap_cleanup(dev); |
498 | drm_ht_remove(&dev->map_hash); | ||
467 | 499 | ||
468 | list_del(&dev->driver_item); | ||
469 | kfree(dev->devname); | 500 | kfree(dev->devname); |
470 | kfree(dev); | 501 | kfree(dev); |
471 | } | 502 | } |
472 | EXPORT_SYMBOL(drm_put_dev); | 503 | EXPORT_SYMBOL(drm_dev_free); |
473 | 504 | ||
474 | void drm_unplug_dev(struct drm_device *dev) | 505 | /** |
506 | * drm_dev_register - Register DRM device | ||
507 | * @dev: Device to register | ||
508 | * | ||
509 | * Register the DRM device @dev with the system, advertise device to user-space | ||
510 | * and start normal device operation. @dev must be allocated via drm_dev_alloc() | ||
511 | * previously. | ||
512 | * | ||
513 | * Never call this twice on any device! | ||
514 | * | ||
515 | * RETURNS: | ||
516 | * 0 on success, negative error code on failure. | ||
517 | */ | ||
518 | int drm_dev_register(struct drm_device *dev, unsigned long flags) | ||
475 | { | 519 | { |
476 | /* for a USB device */ | 520 | int ret; |
477 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
478 | drm_unplug_minor(dev->control); | ||
479 | if (dev->render) | ||
480 | drm_unplug_minor(dev->render); | ||
481 | drm_unplug_minor(dev->primary); | ||
482 | 521 | ||
483 | mutex_lock(&drm_global_mutex); | 522 | mutex_lock(&drm_global_mutex); |
484 | 523 | ||
485 | drm_device_set_unplugged(dev); | 524 | if (dev->driver->bus->agp_init) { |
525 | ret = dev->driver->bus->agp_init(dev); | ||
526 | if (ret) | ||
527 | goto out_unlock; | ||
528 | } | ||
486 | 529 | ||
487 | if (dev->open_count == 0) { | 530 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
488 | drm_put_dev(dev); | 531 | ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); |
532 | if (ret) | ||
533 | goto err_agp; | ||
534 | } | ||
535 | |||
536 | if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { | ||
537 | ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); | ||
538 | if (ret) | ||
539 | goto err_control_node; | ||
540 | } | ||
541 | |||
542 | ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); | ||
543 | if (ret) | ||
544 | goto err_render_node; | ||
545 | |||
546 | if (dev->driver->load) { | ||
547 | ret = dev->driver->load(dev, flags); | ||
548 | if (ret) | ||
549 | goto err_primary_node; | ||
489 | } | 550 | } |
551 | |||
552 | /* setup grouping for legacy outputs */ | ||
553 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
554 | ret = drm_mode_group_init_legacy_group(dev, | ||
555 | &dev->primary->mode_group); | ||
556 | if (ret) | ||
557 | goto err_unload; | ||
558 | } | ||
559 | |||
560 | list_add_tail(&dev->driver_item, &dev->driver->device_list); | ||
561 | |||
562 | ret = 0; | ||
563 | goto out_unlock; | ||
564 | |||
565 | err_unload: | ||
566 | if (dev->driver->unload) | ||
567 | dev->driver->unload(dev); | ||
568 | err_primary_node: | ||
569 | drm_put_minor(dev->primary); | ||
570 | err_render_node: | ||
571 | drm_put_minor(dev->render); | ||
572 | err_control_node: | ||
573 | drm_put_minor(dev->control); | ||
574 | err_agp: | ||
575 | if (dev->driver->bus->agp_destroy) | ||
576 | dev->driver->bus->agp_destroy(dev); | ||
577 | out_unlock: | ||
490 | mutex_unlock(&drm_global_mutex); | 578 | mutex_unlock(&drm_global_mutex); |
579 | return ret; | ||
491 | } | 580 | } |
492 | EXPORT_SYMBOL(drm_unplug_dev); | 581 | EXPORT_SYMBOL(drm_dev_register); |
582 | |||
583 | /** | ||
584 | * drm_dev_unregister - Unregister DRM device | ||
585 | * @dev: Device to unregister | ||
586 | * | ||
587 | * Unregister the DRM device from the system. This does the reverse of | ||
588 | * drm_dev_register() but does not deallocate the device. The caller must call | ||
589 | * drm_dev_free() to free all resources. | ||
590 | */ | ||
591 | void drm_dev_unregister(struct drm_device *dev) | ||
592 | { | ||
593 | struct drm_map_list *r_list, *list_temp; | ||
594 | |||
595 | drm_lastclose(dev); | ||
596 | |||
597 | if (dev->driver->unload) | ||
598 | dev->driver->unload(dev); | ||
599 | |||
600 | if (dev->driver->bus->agp_destroy) | ||
601 | dev->driver->bus->agp_destroy(dev); | ||
602 | |||
603 | drm_vblank_cleanup(dev); | ||
604 | |||
605 | list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) | ||
606 | drm_rmmap(dev, r_list->map); | ||
607 | |||
608 | drm_unplug_minor(dev->control); | ||
609 | drm_unplug_minor(dev->render); | ||
610 | drm_unplug_minor(dev->primary); | ||
611 | |||
612 | list_del(&dev->driver_item); | ||
613 | } | ||
614 | EXPORT_SYMBOL(drm_dev_unregister); | ||