aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-12-09 08:56:56 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-12-10 16:46:19 -0500
commit6449b088dd51dd5aa6b38455888bbf538d21f2fc (patch)
tree5c530eba1f63e47993aad7272f1d63ec4fb00ef0
parent72a93e8dd52c9feea42f1258d555e6070680a347 (diff)
drm: Add fake controlD* symlinks for backwards compat
We thought that no userspace is using them, but oops libdrm is using them to figure out whether a driver supports modesetting. Check out drmCheckModesettingSupported but maybe don't because it's horrible and totally runs counter to where we want to go with libdrm device handling. The function looks in the device hierarchy for whether controlD* exist using the following format string: /sys/bus/pci/devices/%04x:%02x:%02x.%d/drm/controlD%d The "/drm" subdirectory is the glue directory from the sysfs class stuff, and the only way to get at it seems to through kdev->kobj.parent (when kdev is represents e.g. the card0 chardev instance in sysfs). Git grep says we're not the only ones touching that, so I hope it's ok we dig into such internals - I couldn't find a proper interface for getting at the glue directory. Quick git grep shows that at least -amdgpu, -ati are using this. -modesetting do not, and on -intel it's only about the 4th fallback path for device lookup, which is why this didn't blow up earlier. Oh well, we need to keep it working, and the simplest way is to add a symlink at the right place in sysfs from controlD* to card*. v2: - Fix error path handling by adding if (!minor) return checks (David) - Fix the controlD* numbers to match what's been there (David) - Add a comment what exactly userspace minimally needs. - Correct the analysis for -intel (Chris). Fixes: 8a357d10043c ("drm: Nerf DRM_CONTROL nodes") Cc: Dave Airlie <airlied@gmail.com> Reported-and-tested-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Emil Velikov <emil.l.velikov@gmail.com> Reviewed-by: David Herrmann <dh.herrmann@gmail.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: David Herrmann <dh.herrmann@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20161209135656.14881-1-daniel.vetter@ffwll.ch
-rw-r--r--drivers/gpu/drm/drm_drv.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index f74b7d06ec01..a525751b4559 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -647,6 +647,62 @@ void drm_dev_unref(struct drm_device *dev)
647} 647}
648EXPORT_SYMBOL(drm_dev_unref); 648EXPORT_SYMBOL(drm_dev_unref);
649 649
650static int create_compat_control_link(struct drm_device *dev)
651{
652 struct drm_minor *minor;
653 char *name;
654 int ret;
655
656 if (!drm_core_check_feature(dev, DRIVER_MODESET))
657 return 0;
658
659 minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
660 if (!minor)
661 return 0;
662
663 /*
664 * Some existing userspace out there uses the existing of the controlD*
665 * sysfs files to figure out whether it's a modeset driver. It only does
666 * readdir, hence a symlink is sufficient (and the least confusing
667 * option). Otherwise controlD* is entirely unused.
668 *
669 * Old controlD chardev have been allocated in the range
670 * 64-127.
671 */
672 name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
673 if (!name)
674 return -ENOMEM;
675
676 ret = sysfs_create_link(minor->kdev->kobj.parent,
677 &minor->kdev->kobj,
678 name);
679
680 kfree(name);
681
682 return ret;
683}
684
685static void remove_compat_control_link(struct drm_device *dev)
686{
687 struct drm_minor *minor;
688 char *name;
689
690 if (!drm_core_check_feature(dev, DRIVER_MODESET))
691 return;
692
693 minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
694 if (!minor)
695 return;
696
697 name = kasprintf(GFP_KERNEL, "controlD%d", minor->index);
698 if (!name)
699 return;
700
701 sysfs_remove_link(minor->kdev->kobj.parent, name);
702
703 kfree(name);
704}
705
650/** 706/**
651 * drm_dev_register - Register DRM device 707 * drm_dev_register - Register DRM device
652 * @dev: Device to register 708 * @dev: Device to register
@@ -685,6 +741,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
685 if (ret) 741 if (ret)
686 goto err_minors; 742 goto err_minors;
687 743
744 ret = create_compat_control_link(dev);
745 if (ret)
746 goto err_minors;
747
688 if (dev->driver->load) { 748 if (dev->driver->load) {
689 ret = dev->driver->load(dev, flags); 749 ret = dev->driver->load(dev, flags);
690 if (ret) 750 if (ret)
@@ -698,6 +758,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
698 goto out_unlock; 758 goto out_unlock;
699 759
700err_minors: 760err_minors:
761 remove_compat_control_link(dev);
701 drm_minor_unregister(dev, DRM_MINOR_PRIMARY); 762 drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
702 drm_minor_unregister(dev, DRM_MINOR_RENDER); 763 drm_minor_unregister(dev, DRM_MINOR_RENDER);
703 drm_minor_unregister(dev, DRM_MINOR_CONTROL); 764 drm_minor_unregister(dev, DRM_MINOR_CONTROL);
@@ -738,6 +799,7 @@ void drm_dev_unregister(struct drm_device *dev)
738 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 799 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
739 drm_legacy_rmmap(dev, r_list->map); 800 drm_legacy_rmmap(dev, r_list->map);
740 801
802 remove_compat_control_link(dev);
741 drm_minor_unregister(dev, DRM_MINOR_PRIMARY); 803 drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
742 drm_minor_unregister(dev, DRM_MINOR_RENDER); 804 drm_minor_unregister(dev, DRM_MINOR_RENDER);
743 drm_minor_unregister(dev, DRM_MINOR_CONTROL); 805 drm_minor_unregister(dev, DRM_MINOR_CONTROL);