aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_sysfs.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-10-11 00:07:25 -0400
committerDave Airlie <airlied@redhat.com>2013-10-22 04:37:40 -0400
commit5bdebb183c9702a8c57a01dff09337be3de337a6 (patch)
treee4ae9a441e4b2c4739902e4914852696accf1682 /drivers/gpu/drm/drm_sysfs.c
parent14c8d110e083d3a09ccf8cfe18ad22fe1450c2e9 (diff)
drm/sysfs: sort out minor and connector device object lifetimes.
So drm was abusing device lifetimes, by having embedded device structures in the minor and connector it meant that the lifetime of the internal drm objects (drm_minor and drm_connector) were tied to the lifetime of the device files in sysfs, so if something kept those files opened the current code would kfree the objects and things would go downhill from there. Now in reality there is no need for these lifetimes to be so intertwined, especailly with hotplugging of devices where we wish to remove the sysfs and userspace facing pieces before we can unwind the internal objects due to open userspace files or mmaps, so split the objects out so the struct device is no longer embedded and do what fbdev does and just allocate and remove the sysfs inodes separately. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_sysfs.c')
-rw-r--r--drivers/gpu/drm/drm_sysfs.c94
1 files changed, 34 insertions, 60 deletions
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 2290b3b73832..dae42c79154f 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -22,8 +22,8 @@
22#include <drm/drm_core.h> 22#include <drm/drm_core.h>
23#include <drm/drmP.h> 23#include <drm/drmP.h>
24 24
25#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) 25#define to_drm_minor(d) dev_get_drvdata(d)
26#define to_drm_connector(d) container_of(d, struct drm_connector, kdev) 26#define to_drm_connector(d) dev_get_drvdata(d)
27 27
28static struct device_type drm_sysfs_device_minor = { 28static struct device_type drm_sysfs_device_minor = {
29 .name = "drm_minor" 29 .name = "drm_minor"
@@ -162,20 +162,6 @@ void drm_sysfs_destroy(void)
162 drm_class = NULL; 162 drm_class = NULL;
163} 163}
164 164
165/**
166 * drm_sysfs_device_release - do nothing
167 * @dev: Linux device
168 *
169 * Normally, this would free the DRM device associated with @dev, along
170 * with cleaning up any other stuff. But we do that in the DRM core, so
171 * this function can just return and hope that the core does its job.
172 */
173static void drm_sysfs_device_release(struct device *dev)
174{
175 memset(dev, 0, sizeof(struct device));
176 return;
177}
178
179/* 165/*
180 * Connector properties 166 * Connector properties
181 */ 167 */
@@ -394,29 +380,26 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
394 int i; 380 int i;
395 int ret; 381 int ret;
396 382
397 /* We shouldn't get called more than once for the same connector */ 383 if (connector->kdev)
398 BUG_ON(device_is_registered(&connector->kdev)); 384 return 0;
399
400 connector->kdev.parent = &dev->primary->kdev;
401 connector->kdev.class = drm_class;
402 connector->kdev.release = drm_sysfs_device_release;
403 385
386 /* We shouldn't get called more than once for the same connector */
387 connector->kdev = device_create(drm_class, dev->primary->kdev,
388 0, connector, "card%d-%s",
389 dev->primary->index, drm_get_connector_name(connector));
404 DRM_DEBUG("adding \"%s\" to sysfs\n", 390 DRM_DEBUG("adding \"%s\" to sysfs\n",
405 drm_get_connector_name(connector)); 391 drm_get_connector_name(connector));
406 392
407 dev_set_name(&connector->kdev, "card%d-%s", 393 if (IS_ERR(connector->kdev)) {
408 dev->primary->index, drm_get_connector_name(connector)); 394 DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
409 ret = device_register(&connector->kdev); 395 ret = PTR_ERR(connector->kdev);
410
411 if (ret) {
412 DRM_ERROR("failed to register connector device: %d\n", ret);
413 goto out; 396 goto out;
414 } 397 }
415 398
416 /* Standard attributes */ 399 /* Standard attributes */
417 400
418 for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) { 401 for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) {
419 ret = device_create_file(&connector->kdev, &connector_attrs[attr_cnt]); 402 ret = device_create_file(connector->kdev, &connector_attrs[attr_cnt]);
420 if (ret) 403 if (ret)
421 goto err_out_files; 404 goto err_out_files;
422 } 405 }
@@ -433,7 +416,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
433 case DRM_MODE_CONNECTOR_Component: 416 case DRM_MODE_CONNECTOR_Component:
434 case DRM_MODE_CONNECTOR_TV: 417 case DRM_MODE_CONNECTOR_TV:
435 for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) { 418 for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) {
436 ret = device_create_file(&connector->kdev, &connector_attrs_opt1[opt_cnt]); 419 ret = device_create_file(connector->kdev, &connector_attrs_opt1[opt_cnt]);
437 if (ret) 420 if (ret)
438 goto err_out_files; 421 goto err_out_files;
439 } 422 }
@@ -442,7 +425,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
442 break; 425 break;
443 } 426 }
444 427
445 ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); 428 ret = sysfs_create_bin_file(&connector->kdev->kobj, &edid_attr);
446 if (ret) 429 if (ret)
447 goto err_out_files; 430 goto err_out_files;
448 431
@@ -453,10 +436,11 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
453 436
454err_out_files: 437err_out_files:
455 for (i = 0; i < opt_cnt; i++) 438 for (i = 0; i < opt_cnt; i++)
456 device_remove_file(&connector->kdev, &connector_attrs_opt1[i]); 439 device_remove_file(connector->kdev, &connector_attrs_opt1[i]);
457 for (i = 0; i < attr_cnt; i++) 440 for (i = 0; i < attr_cnt; i++)
458 device_remove_file(&connector->kdev, &connector_attrs[i]); 441 device_remove_file(connector->kdev, &connector_attrs[i]);
459 device_unregister(&connector->kdev); 442 put_device(connector->kdev);
443 device_unregister(connector->kdev);
460 444
461out: 445out:
462 return ret; 446 return ret;
@@ -480,16 +464,17 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
480{ 464{
481 int i; 465 int i;
482 466
483 if (!connector->kdev.parent) 467 if (!connector->kdev)
484 return; 468 return;
485 DRM_DEBUG("removing \"%s\" from sysfs\n", 469 DRM_DEBUG("removing \"%s\" from sysfs\n",
486 drm_get_connector_name(connector)); 470 drm_get_connector_name(connector));
487 471
488 for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) 472 for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
489 device_remove_file(&connector->kdev, &connector_attrs[i]); 473 device_remove_file(connector->kdev, &connector_attrs[i]);
490 sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); 474 sysfs_remove_bin_file(&connector->kdev->kobj, &edid_attr);
491 device_unregister(&connector->kdev); 475 put_device(connector->kdev);
492 connector->kdev.parent = NULL; 476 device_unregister(connector->kdev);
477 connector->kdev = NULL;
493} 478}
494EXPORT_SYMBOL(drm_sysfs_connector_remove); 479EXPORT_SYMBOL(drm_sysfs_connector_remove);
495 480
@@ -508,7 +493,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
508 493
509 DRM_DEBUG("generating hotplug event\n"); 494 DRM_DEBUG("generating hotplug event\n");
510 495
511 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); 496 kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
512} 497}
513EXPORT_SYMBOL(drm_sysfs_hotplug_event); 498EXPORT_SYMBOL(drm_sysfs_hotplug_event);
514 499
@@ -523,15 +508,8 @@ EXPORT_SYMBOL(drm_sysfs_hotplug_event);
523 */ 508 */
524int drm_sysfs_device_add(struct drm_minor *minor) 509int drm_sysfs_device_add(struct drm_minor *minor)
525{ 510{
526 int err;
527 char *minor_str; 511 char *minor_str;
528 512
529 minor->kdev.parent = minor->dev->dev;
530
531 minor->kdev.class = drm_class;
532 minor->kdev.release = drm_sysfs_device_release;
533 minor->kdev.devt = minor->device;
534 minor->kdev.type = &drm_sysfs_device_minor;
535 if (minor->type == DRM_MINOR_CONTROL) 513 if (minor->type == DRM_MINOR_CONTROL)
536 minor_str = "controlD%d"; 514 minor_str = "controlD%d";
537 else if (minor->type == DRM_MINOR_RENDER) 515 else if (minor->type == DRM_MINOR_RENDER)
@@ -539,18 +517,14 @@ int drm_sysfs_device_add(struct drm_minor *minor)
539 else 517 else
540 minor_str = "card%d"; 518 minor_str = "card%d";
541 519
542 dev_set_name(&minor->kdev, minor_str, minor->index); 520 minor->kdev = device_create(drm_class, minor->dev->dev,
543 521 MKDEV(DRM_MAJOR, minor->index),
544 err = device_register(&minor->kdev); 522 minor, minor_str, minor->index);
545 if (err) { 523 if (IS_ERR(minor->kdev)) {
546 DRM_ERROR("device add failed: %d\n", err); 524 DRM_ERROR("device create failed %ld\n", PTR_ERR(minor->kdev));
547 goto err_out; 525 return PTR_ERR(minor->kdev);
548 } 526 }
549
550 return 0; 527 return 0;
551
552err_out:
553 return err;
554} 528}
555 529
556/** 530/**
@@ -562,9 +536,9 @@ err_out:
562 */ 536 */
563void drm_sysfs_device_remove(struct drm_minor *minor) 537void drm_sysfs_device_remove(struct drm_minor *minor)
564{ 538{
565 if (minor->kdev.parent) 539 if (minor->kdev)
566 device_unregister(&minor->kdev); 540 device_destroy(drm_class, MKDEV(DRM_MAJOR, minor->index));
567 minor->kdev.parent = NULL; 541 minor->kdev = NULL;
568} 542}
569 543
570 544