drm/sysfs: fix hotplug regression since lifetime changes
authorDavid Herrmann <dh.herrmann@gmail.com>
Thu, 21 Nov 2013 10:50:50 +0000 (20:50 +1000)
committerDave Airlie <airlied@gmail.com>
Thu, 21 Nov 2013 11:10:00 +0000 (21:10 +1000)
airlied:
The lifetime changes introduced in 5bdebb183c9702a8c57a01dff09337be3de337a6
tried to use device_create, however that led to the regression where dev->type
wasn't getting set correctly. First attempt at fixing it would have led to
a race, so this undoes the device_createa work and does it all manually
making sure the dev->type is setup before we register the device.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_sysfs.c

index 1a35ea53106b860f5a039ec0df9748cad5729da1..bd2bca395792a600deda6c6f2a1a28314ea89374 100644 (file)
@@ -489,6 +489,11 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 
+static void drm_sysfs_release(struct device *dev)
+{
+       kfree(dev);
+}
+
 /**
  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
  * @dev: DRM device to be added
@@ -501,6 +506,7 @@ EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 int drm_sysfs_device_add(struct drm_minor *minor)
 {
        char *minor_str;
+       int r;
 
        if (minor->type == DRM_MINOR_CONTROL)
                minor_str = "controlD%d";
@@ -509,14 +515,34 @@ int drm_sysfs_device_add(struct drm_minor *minor)
         else
                 minor_str = "card%d";
 
-       minor->kdev = device_create(drm_class, minor->dev->dev,
-                                   MKDEV(DRM_MAJOR, minor->index),
-                                   minor, minor_str, minor->index);
-       if (IS_ERR(minor->kdev)) {
-               DRM_ERROR("device create failed %ld\n", PTR_ERR(minor->kdev));
-               return PTR_ERR(minor->kdev);
+       minor->kdev = kzalloc(sizeof(*minor->kdev), GFP_KERNEL);
+       if (!minor->dev) {
+               r = -ENOMEM;
+               goto error;
        }
+
+       device_initialize(minor->kdev);
+       minor->kdev->devt = MKDEV(DRM_MAJOR, minor->index);
+       minor->kdev->class = drm_class;
+       minor->kdev->type = &drm_sysfs_device_minor;
+       minor->kdev->parent = minor->dev->dev;
+       minor->kdev->release = drm_sysfs_release;
+       dev_set_drvdata(minor->kdev, minor);
+
+       r = dev_set_name(minor->kdev, minor_str, minor->index);
+       if (r < 0)
+               goto error;
+
+       r = device_add(minor->kdev);
+       if (r < 0)
+               goto error;
+
        return 0;
+
+error:
+       DRM_ERROR("device create failed %d\n", r);
+       put_device(minor->kdev);
+       return r;
 }
 
 /**
@@ -529,7 +555,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
 void drm_sysfs_device_remove(struct drm_minor *minor)
 {
        if (minor->kdev)
-               device_destroy(drm_class, MKDEV(DRM_MAJOR, minor->index));
+               device_unregister(minor->kdev);
        minor->kdev = NULL;
 }