diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 54 |
1 files changed, 28 insertions, 26 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a6e42433ef0e..26feb2f8453f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -528,11 +528,11 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) | |||
528 | int drm_crtc_helper_set_config(struct drm_mode_set *set) | 528 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
529 | { | 529 | { |
530 | struct drm_device *dev; | 530 | struct drm_device *dev; |
531 | struct drm_crtc *new_crtc; | 531 | struct drm_crtc **save_encoder_crtcs, *new_crtc; |
532 | struct drm_encoder *save_encoders, *new_encoder, *encoder; | 532 | struct drm_encoder **save_connector_encoders, *new_encoder, *encoder; |
533 | bool mode_changed = false; /* if true do a full mode set */ | 533 | bool mode_changed = false; /* if true do a full mode set */ |
534 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ | 534 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
535 | struct drm_connector *save_connectors, *connector; | 535 | struct drm_connector *connector; |
536 | int count = 0, ro, fail = 0; | 536 | int count = 0, ro, fail = 0; |
537 | const struct drm_crtc_helper_funcs *crtc_funcs; | 537 | const struct drm_crtc_helper_funcs *crtc_funcs; |
538 | struct drm_mode_set save_set; | 538 | struct drm_mode_set save_set; |
@@ -574,15 +574,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
574 | * Allocate space for the backup of all (non-pointer) encoder and | 574 | * Allocate space for the backup of all (non-pointer) encoder and |
575 | * connector data. | 575 | * connector data. |
576 | */ | 576 | */ |
577 | save_encoders = kzalloc(dev->mode_config.num_encoder * | 577 | save_encoder_crtcs = kzalloc(dev->mode_config.num_encoder * |
578 | sizeof(struct drm_encoder), GFP_KERNEL); | 578 | sizeof(struct drm_crtc *), GFP_KERNEL); |
579 | if (!save_encoders) | 579 | if (!save_encoder_crtcs) |
580 | return -ENOMEM; | 580 | return -ENOMEM; |
581 | 581 | ||
582 | save_connectors = kzalloc(dev->mode_config.num_connector * | 582 | save_connector_encoders = kzalloc(dev->mode_config.num_connector * |
583 | sizeof(struct drm_connector), GFP_KERNEL); | 583 | sizeof(struct drm_encoder *), GFP_KERNEL); |
584 | if (!save_connectors) { | 584 | if (!save_connector_encoders) { |
585 | kfree(save_encoders); | 585 | kfree(save_encoder_crtcs); |
586 | return -ENOMEM; | 586 | return -ENOMEM; |
587 | } | 587 | } |
588 | 588 | ||
@@ -593,12 +593,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
593 | */ | 593 | */ |
594 | count = 0; | 594 | count = 0; |
595 | drm_for_each_encoder(encoder, dev) { | 595 | drm_for_each_encoder(encoder, dev) { |
596 | save_encoders[count++] = *encoder; | 596 | save_encoder_crtcs[count++] = encoder->crtc; |
597 | } | 597 | } |
598 | 598 | ||
599 | count = 0; | 599 | count = 0; |
600 | drm_for_each_connector(connector, dev) { | 600 | drm_for_each_connector(connector, dev) { |
601 | save_connectors[count++] = *connector; | 601 | save_connector_encoders[count++] = connector->encoder; |
602 | } | 602 | } |
603 | 603 | ||
604 | save_set.crtc = set->crtc; | 604 | save_set.crtc = set->crtc; |
@@ -631,8 +631,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
631 | mode_changed = true; | 631 | mode_changed = true; |
632 | } | 632 | } |
633 | 633 | ||
634 | /* take a reference on all connectors in set */ | 634 | /* take a reference on all unbound connectors in set, reuse the |
635 | * already taken reference for bound connectors | ||
636 | */ | ||
635 | for (ro = 0; ro < set->num_connectors; ro++) { | 637 | for (ro = 0; ro < set->num_connectors; ro++) { |
638 | if (set->connectors[ro]->encoder) | ||
639 | continue; | ||
636 | drm_connector_reference(set->connectors[ro]); | 640 | drm_connector_reference(set->connectors[ro]); |
637 | } | 641 | } |
638 | 642 | ||
@@ -754,30 +758,28 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
754 | } | 758 | } |
755 | } | 759 | } |
756 | 760 | ||
757 | /* after fail drop reference on all connectors in save set */ | 761 | kfree(save_connector_encoders); |
758 | count = 0; | 762 | kfree(save_encoder_crtcs); |
759 | drm_for_each_connector(connector, dev) { | ||
760 | drm_connector_unreference(&save_connectors[count++]); | ||
761 | } | ||
762 | |||
763 | kfree(save_connectors); | ||
764 | kfree(save_encoders); | ||
765 | return 0; | 763 | return 0; |
766 | 764 | ||
767 | fail: | 765 | fail: |
768 | /* Restore all previous data. */ | 766 | /* Restore all previous data. */ |
769 | count = 0; | 767 | count = 0; |
770 | drm_for_each_encoder(encoder, dev) { | 768 | drm_for_each_encoder(encoder, dev) { |
771 | *encoder = save_encoders[count++]; | 769 | encoder->crtc = save_encoder_crtcs[count++]; |
772 | } | 770 | } |
773 | 771 | ||
774 | count = 0; | 772 | count = 0; |
775 | drm_for_each_connector(connector, dev) { | 773 | drm_for_each_connector(connector, dev) { |
776 | *connector = save_connectors[count++]; | 774 | connector->encoder = save_connector_encoders[count++]; |
777 | } | 775 | } |
778 | 776 | ||
779 | /* after fail drop reference on all connectors in set */ | 777 | /* after fail drop reference on all unbound connectors in set, let |
778 | * bound connectors keep their reference | ||
779 | */ | ||
780 | for (ro = 0; ro < set->num_connectors; ro++) { | 780 | for (ro = 0; ro < set->num_connectors; ro++) { |
781 | if (set->connectors[ro]->encoder) | ||
782 | continue; | ||
781 | drm_connector_unreference(set->connectors[ro]); | 783 | drm_connector_unreference(set->connectors[ro]); |
782 | } | 784 | } |
783 | 785 | ||
@@ -787,8 +789,8 @@ fail: | |||
787 | save_set.y, save_set.fb)) | 789 | save_set.y, save_set.fb)) |
788 | DRM_ERROR("failed to restore config after modeset failure\n"); | 790 | DRM_ERROR("failed to restore config after modeset failure\n"); |
789 | 791 | ||
790 | kfree(save_connectors); | 792 | kfree(save_connector_encoders); |
791 | kfree(save_encoders); | 793 | kfree(save_encoder_crtcs); |
792 | return ret; | 794 | return ret; |
793 | } | 795 | } |
794 | EXPORT_SYMBOL(drm_crtc_helper_set_config); | 796 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |