aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2014-07-23 05:38:38 -0400
committerDavid Herrmann <dh.herrmann@gmail.com>2014-08-05 10:08:21 -0400
commite17280758cc0b4f3d7065554006adcb87448f6c0 (patch)
tree71641f392c6ab39518ac56b2efa4763e7f5ecdd8
parentf1b8596283f681b82546d6302bc7c372fdb2d422 (diff)
drm: make sysfs device always available for minors
For each minor we allocate a sysfs device as minor->kdev. Currently, this is allocated and registered in drm_minor_register(). This makes it impossible to add sysfs-attributes to the device before it is registered. Therefore, they are not added atomically, nor can we move device_add() *after* ->load() is called. This patch makes minor->kdev available early, but only adds the device during minor-registration. Note that the registration is still called before ->load() as debugfs needs to be split, too. This will be fixed in follow-ups. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r--drivers/gpu/drm/drm_stub.c22
-rw-r--r--drivers/gpu/drm/drm_sysfs.c90
-rw-r--r--include/drm/drmP.h3
3 files changed, 54 insertions, 61 deletions
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 8b24db51116e..09c6bfb86a66 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -281,9 +281,19 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
281 281
282 minor->index = r; 282 minor->index = r;
283 283
284 minor->kdev = drm_sysfs_minor_alloc(minor);
285 if (IS_ERR(minor->kdev)) {
286 r = PTR_ERR(minor->kdev);
287 goto err_index;
288 }
289
284 *drm_minor_get_slot(dev, type) = minor; 290 *drm_minor_get_slot(dev, type) = minor;
285 return 0; 291 return 0;
286 292
293err_index:
294 spin_lock_irqsave(&drm_minor_lock, flags);
295 idr_remove(&drm_minors_idr, minor->index);
296 spin_unlock_irqrestore(&drm_minor_lock, flags);
287err_free: 297err_free:
288 kfree(minor); 298 kfree(minor);
289 return r; 299 return r;
@@ -300,6 +310,7 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type)
300 return; 310 return;
301 311
302 drm_mode_group_destroy(&minor->mode_group); 312 drm_mode_group_destroy(&minor->mode_group);
313 put_device(minor->kdev);
303 314
304 spin_lock_irqsave(&drm_minor_lock, flags); 315 spin_lock_irqsave(&drm_minor_lock, flags);
305 idr_remove(&drm_minors_idr, minor->index); 316 idr_remove(&drm_minors_idr, minor->index);
@@ -327,11 +338,9 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
327 return ret; 338 return ret;
328 } 339 }
329 340
330 ret = drm_sysfs_device_add(minor); 341 ret = device_add(minor->kdev);
331 if (ret) { 342 if (ret)
332 DRM_ERROR("DRM: Error sysfs_device_add.\n");
333 goto err_debugfs; 343 goto err_debugfs;
334 }
335 344
336 /* replace NULL with @minor so lookups will succeed from now on */ 345 /* replace NULL with @minor so lookups will succeed from now on */
337 spin_lock_irqsave(&drm_minor_lock, flags); 346 spin_lock_irqsave(&drm_minor_lock, flags);
@@ -352,7 +361,7 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
352 unsigned long flags; 361 unsigned long flags;
353 362
354 minor = *drm_minor_get_slot(dev, type); 363 minor = *drm_minor_get_slot(dev, type);
355 if (!minor || !minor->kdev) 364 if (!minor || !device_is_registered(minor->kdev))
356 return; 365 return;
357 366
358 /* replace @minor with NULL so lookups will fail from now on */ 367 /* replace @minor with NULL so lookups will fail from now on */
@@ -360,8 +369,9 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
360 idr_replace(&drm_minors_idr, NULL, minor->index); 369 idr_replace(&drm_minors_idr, NULL, minor->index);
361 spin_unlock_irqrestore(&drm_minor_lock, flags); 370 spin_unlock_irqrestore(&drm_minor_lock, flags);
362 371
372 device_del(minor->kdev);
373 dev_set_drvdata(minor->kdev, NULL); /* safety belt */
363 drm_debugfs_cleanup(minor); 374 drm_debugfs_cleanup(minor);
364 drm_sysfs_device_remove(minor);
365} 375}
366 376
367/** 377/**
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 7827dad8fcf4..ab1a5f6dde8a 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -493,71 +493,55 @@ static void drm_sysfs_release(struct device *dev)
493} 493}
494 494
495/** 495/**
496 * drm_sysfs_device_add - adds a class device to sysfs for a character driver 496 * drm_sysfs_minor_alloc() - Allocate sysfs device for given minor
497 * @dev: DRM device to be added 497 * @minor: minor to allocate sysfs device for
498 * @head: DRM head in question
499 * 498 *
500 * Add a DRM device to the DRM's device model class. We use @dev's PCI device 499 * This allocates a new sysfs device for @minor and returns it. The device is
501 * as the parent for the Linux device, and make sure it has a file containing 500 * not registered nor linked. The caller has to use device_add() and
502 * the driver we're using (for userspace compatibility). 501 * device_del() to register and unregister it.
502 *
503 * Note that dev_get_drvdata() on the new device will return the minor.
504 * However, the device does not hold a ref-count to the minor nor to the
505 * underlying drm_device. This is unproblematic as long as you access the
506 * private data only in sysfs callbacks. device_del() disables those
507 * synchronously, so they cannot be called after you cleanup a minor.
503 */ 508 */
504int drm_sysfs_device_add(struct drm_minor *minor) 509struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
505{ 510{
506 char *minor_str; 511 const char *minor_str;
512 struct device *kdev;
507 int r; 513 int r;
508 514
509 if (minor->type == DRM_MINOR_CONTROL) 515 if (minor->type == DRM_MINOR_CONTROL)
510 minor_str = "controlD%d"; 516 minor_str = "controlD%d";
511 else if (minor->type == DRM_MINOR_RENDER) 517 else if (minor->type == DRM_MINOR_RENDER)
512 minor_str = "renderD%d"; 518 minor_str = "renderD%d";
513 else 519 else
514 minor_str = "card%d"; 520 minor_str = "card%d";
515 521
516 minor->kdev = kzalloc(sizeof(*minor->kdev), GFP_KERNEL); 522 kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
517 if (!minor->kdev) { 523 if (!kdev)
518 r = -ENOMEM; 524 return ERR_PTR(-ENOMEM);
519 goto error; 525
520 } 526 device_initialize(kdev);
521 527 kdev->devt = MKDEV(DRM_MAJOR, minor->index);
522 device_initialize(minor->kdev); 528 kdev->class = drm_class;
523 minor->kdev->devt = MKDEV(DRM_MAJOR, minor->index); 529 kdev->type = &drm_sysfs_device_minor;
524 minor->kdev->class = drm_class; 530 kdev->parent = minor->dev->dev;
525 minor->kdev->type = &drm_sysfs_device_minor; 531 kdev->release = drm_sysfs_release;
526 minor->kdev->parent = minor->dev->dev; 532 dev_set_drvdata(kdev, minor);
527 minor->kdev->release = drm_sysfs_release; 533
528 dev_set_drvdata(minor->kdev, minor); 534 r = dev_set_name(kdev, minor_str, minor->index);
529
530 r = dev_set_name(minor->kdev, minor_str, minor->index);
531 if (r < 0) 535 if (r < 0)
532 goto error; 536 goto err_free;
533
534 r = device_add(minor->kdev);
535 if (r < 0)
536 goto error;
537
538 return 0;
539 537
540error: 538 return kdev;
541 DRM_ERROR("device create failed %d\n", r);
542 put_device(minor->kdev);
543 return r;
544}
545 539
546/** 540err_free:
547 * drm_sysfs_device_remove - remove DRM device 541 put_device(kdev);
548 * @dev: DRM device to remove 542 return ERR_PTR(r);
549 *
550 * This call unregisters and cleans up a class device that was created with a
551 * call to drm_sysfs_device_add()
552 */
553void drm_sysfs_device_remove(struct drm_minor *minor)
554{
555 if (minor->kdev)
556 device_unregister(minor->kdev);
557 minor->kdev = NULL;
558} 543}
559 544
560
561/** 545/**
562 * drm_class_device_register - Register a struct device in the drm class. 546 * drm_class_device_register - Register a struct device in the drm class.
563 * 547 *
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index c480b448ce65..458385ec15f3 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1502,9 +1502,8 @@ extern int drm_pci_set_unique(struct drm_device *dev,
1502struct drm_sysfs_class; 1502struct drm_sysfs_class;
1503extern struct class *drm_sysfs_create(struct module *owner, char *name); 1503extern struct class *drm_sysfs_create(struct module *owner, char *name);
1504extern void drm_sysfs_destroy(void); 1504extern void drm_sysfs_destroy(void);
1505extern int drm_sysfs_device_add(struct drm_minor *minor); 1505extern struct device *drm_sysfs_minor_alloc(struct drm_minor *minor);
1506extern void drm_sysfs_hotplug_event(struct drm_device *dev); 1506extern void drm_sysfs_hotplug_event(struct drm_device *dev);
1507extern void drm_sysfs_device_remove(struct drm_minor *minor);
1508extern int drm_sysfs_connector_add(struct drm_connector *connector); 1507extern int drm_sysfs_connector_add(struct drm_connector *connector);
1509extern void drm_sysfs_connector_remove(struct drm_connector *connector); 1508extern void drm_sysfs_connector_remove(struct drm_connector *connector);
1510 1509