diff options
Diffstat (limited to 'drivers/gpu/drm/drm_stub.c')
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index c23eaf6442ff..dc2c6095d850 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
@@ -31,8 +31,10 @@ | |||
31 | * DEALINGS IN THE SOFTWARE. | 31 | * DEALINGS IN THE SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/fs.h> | ||
34 | #include <linux/module.h> | 35 | #include <linux/module.h> |
35 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/mount.h> | ||
36 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
37 | #include <drm/drmP.h> | 39 | #include <drm/drmP.h> |
38 | #include <drm/drm_core.h> | 40 | #include <drm/drm_core.h> |
@@ -459,6 +461,78 @@ void drm_unplug_dev(struct drm_device *dev) | |||
459 | } | 461 | } |
460 | EXPORT_SYMBOL(drm_unplug_dev); | 462 | EXPORT_SYMBOL(drm_unplug_dev); |
461 | 463 | ||
464 | /* | ||
465 | * DRM internal mount | ||
466 | * We want to be able to allocate our own "struct address_space" to control | ||
467 | * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow | ||
468 | * stand-alone address_space objects, so we need an underlying inode. As there | ||
469 | * is no way to allocate an independent inode easily, we need a fake internal | ||
470 | * VFS mount-point. | ||
471 | * | ||
472 | * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free() | ||
473 | * frees it again. You are allowed to use iget() and iput() to get references to | ||
474 | * the inode. But each drm_fs_inode_new() call must be paired with exactly one | ||
475 | * drm_fs_inode_free() call (which does not have to be the last iput()). | ||
476 | * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it | ||
477 | * between multiple inode-users. You could, technically, call | ||
478 | * iget() + drm_fs_inode_free() directly after alloc and sometime later do an | ||
479 | * iput(), but this way you'd end up with a new vfsmount for each inode. | ||
480 | */ | ||
481 | |||
482 | static int drm_fs_cnt; | ||
483 | static struct vfsmount *drm_fs_mnt; | ||
484 | |||
485 | static const struct dentry_operations drm_fs_dops = { | ||
486 | .d_dname = simple_dname, | ||
487 | }; | ||
488 | |||
489 | static const struct super_operations drm_fs_sops = { | ||
490 | .statfs = simple_statfs, | ||
491 | }; | ||
492 | |||
493 | static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags, | ||
494 | const char *dev_name, void *data) | ||
495 | { | ||
496 | return mount_pseudo(fs_type, | ||
497 | "drm:", | ||
498 | &drm_fs_sops, | ||
499 | &drm_fs_dops, | ||
500 | 0x010203ff); | ||
501 | } | ||
502 | |||
503 | static struct file_system_type drm_fs_type = { | ||
504 | .name = "drm", | ||
505 | .owner = THIS_MODULE, | ||
506 | .mount = drm_fs_mount, | ||
507 | .kill_sb = kill_anon_super, | ||
508 | }; | ||
509 | |||
510 | static struct inode *drm_fs_inode_new(void) | ||
511 | { | ||
512 | struct inode *inode; | ||
513 | int r; | ||
514 | |||
515 | r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt); | ||
516 | if (r < 0) { | ||
517 | DRM_ERROR("Cannot mount pseudo fs: %d\n", r); | ||
518 | return ERR_PTR(r); | ||
519 | } | ||
520 | |||
521 | inode = alloc_anon_inode(drm_fs_mnt->mnt_sb); | ||
522 | if (IS_ERR(inode)) | ||
523 | simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); | ||
524 | |||
525 | return inode; | ||
526 | } | ||
527 | |||
528 | static void drm_fs_inode_free(struct inode *inode) | ||
529 | { | ||
530 | if (inode) { | ||
531 | iput(inode); | ||
532 | simple_release_fs(&drm_fs_mnt, &drm_fs_cnt); | ||
533 | } | ||
534 | } | ||
535 | |||
462 | /** | 536 | /** |
463 | * drm_dev_alloc - Allocate new drm device | 537 | * drm_dev_alloc - Allocate new drm device |
464 | * @driver: DRM driver to allocate device for | 538 | * @driver: DRM driver to allocate device for |
@@ -499,6 +573,13 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, | |||
499 | mutex_init(&dev->struct_mutex); | 573 | mutex_init(&dev->struct_mutex); |
500 | mutex_init(&dev->ctxlist_mutex); | 574 | mutex_init(&dev->ctxlist_mutex); |
501 | 575 | ||
576 | dev->anon_inode = drm_fs_inode_new(); | ||
577 | if (IS_ERR(dev->anon_inode)) { | ||
578 | ret = PTR_ERR(dev->anon_inode); | ||
579 | DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret); | ||
580 | goto err_free; | ||
581 | } | ||
582 | |||
502 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 583 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
503 | ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); | 584 | ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); |
504 | if (ret) | 585 | if (ret) |
@@ -542,6 +623,8 @@ err_minors: | |||
542 | drm_minor_free(dev, DRM_MINOR_LEGACY); | 623 | drm_minor_free(dev, DRM_MINOR_LEGACY); |
543 | drm_minor_free(dev, DRM_MINOR_RENDER); | 624 | drm_minor_free(dev, DRM_MINOR_RENDER); |
544 | drm_minor_free(dev, DRM_MINOR_CONTROL); | 625 | drm_minor_free(dev, DRM_MINOR_CONTROL); |
626 | drm_fs_inode_free(dev->anon_inode); | ||
627 | err_free: | ||
545 | kfree(dev); | 628 | kfree(dev); |
546 | return NULL; | 629 | return NULL; |
547 | } | 630 | } |
@@ -556,6 +639,7 @@ static void drm_dev_release(struct kref *ref) | |||
556 | 639 | ||
557 | drm_ctxbitmap_cleanup(dev); | 640 | drm_ctxbitmap_cleanup(dev); |
558 | drm_ht_remove(&dev->map_hash); | 641 | drm_ht_remove(&dev->map_hash); |
642 | drm_fs_inode_free(dev->anon_inode); | ||
559 | 643 | ||
560 | drm_minor_free(dev, DRM_MINOR_LEGACY); | 644 | drm_minor_free(dev, DRM_MINOR_LEGACY); |
561 | drm_minor_free(dev, DRM_MINOR_RENDER); | 645 | drm_minor_free(dev, DRM_MINOR_RENDER); |