diff options
author | Maarten Maathuis <madman2003@gmail.com> | 2009-08-27 04:18:29 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-08-30 19:09:29 -0400 |
commit | e67aae79f93d9584aaa24d2a2c76383e9d588f98 (patch) | |
tree | 436ea43c3fdf3b99ae76b61dff47998c765a9cd4 /drivers/gpu/drm/drm_crtc_helper.c | |
parent | 689d7c2a1127378854c7d7ea8d7c81238a824240 (diff) |
drm/crtc_helper: replace modeset fail path with something simpler
- The previous system was not very transparent, nor flexible.
- This is needed to be able to fix a few bugs in the mechanism.
Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 86 |
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a06c5f52c289..a3837b39bb8f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -704,13 +704,12 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode); | |||
704 | int drm_crtc_helper_set_config(struct drm_mode_set *set) | 704 | int drm_crtc_helper_set_config(struct drm_mode_set *set) |
705 | { | 705 | { |
706 | struct drm_device *dev; | 706 | struct drm_device *dev; |
707 | struct drm_crtc **save_crtcs, *new_crtc; | 707 | struct drm_crtc *save_crtcs, *new_crtc, *crtc; |
708 | struct drm_encoder **save_encoders, *new_encoder; | 708 | struct drm_encoder *save_encoders, *new_encoder, *encoder; |
709 | struct drm_framebuffer *old_fb = NULL; | 709 | struct drm_framebuffer *old_fb = NULL; |
710 | bool save_enabled; | ||
711 | bool mode_changed = false; /* if true do a full mode set */ | 710 | bool mode_changed = false; /* if true do a full mode set */ |
712 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ | 711 | bool fb_changed = false; /* if true and !mode_changed just do a flip */ |
713 | struct drm_connector *connector; | 712 | struct drm_connector *save_connectors, *connector; |
714 | int count = 0, ro, fail = 0; | 713 | int count = 0, ro, fail = 0; |
715 | struct drm_crtc_helper_funcs *crtc_funcs; | 714 | struct drm_crtc_helper_funcs *crtc_funcs; |
716 | int ret = 0; | 715 | int ret = 0; |
@@ -735,25 +734,47 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
735 | 734 | ||
736 | dev = set->crtc->dev; | 735 | dev = set->crtc->dev; |
737 | 736 | ||
738 | /* save previous config */ | 737 | /* Allocate space for the backup of all (non-pointer) crtc, encoder and |
739 | save_enabled = set->crtc->enabled; | 738 | * connector data. */ |
740 | 739 | save_crtcs = kzalloc(dev->mode_config.num_crtc * | |
741 | /* | 740 | sizeof(struct drm_crtc), GFP_KERNEL); |
742 | * We do mode_config.num_connectors here since we'll look at the | ||
743 | * CRTC and encoder associated with each connector later. | ||
744 | */ | ||
745 | save_crtcs = kzalloc(dev->mode_config.num_connector * | ||
746 | sizeof(struct drm_crtc *), GFP_KERNEL); | ||
747 | if (!save_crtcs) | 741 | if (!save_crtcs) |
748 | return -ENOMEM; | 742 | return -ENOMEM; |
749 | 743 | ||
750 | save_encoders = kzalloc(dev->mode_config.num_connector * | 744 | save_encoders = kzalloc(dev->mode_config.num_encoder * |
751 | sizeof(struct drm_encoders *), GFP_KERNEL); | 745 | sizeof(struct drm_encoder), GFP_KERNEL); |
752 | if (!save_encoders) { | 746 | if (!save_encoders) { |
753 | kfree(save_crtcs); | 747 | kfree(save_crtcs); |
754 | return -ENOMEM; | 748 | return -ENOMEM; |
755 | } | 749 | } |
756 | 750 | ||
751 | save_connectors = kzalloc(dev->mode_config.num_connector * | ||
752 | sizeof(struct drm_connector), GFP_KERNEL); | ||
753 | if (!save_connectors) { | ||
754 | kfree(save_crtcs); | ||
755 | kfree(save_encoders); | ||
756 | return -ENOMEM; | ||
757 | } | ||
758 | |||
759 | /* Copy data. Note that driver private data is not affected. | ||
760 | * Should anything bad happen only the expected state is | ||
761 | * restored, not the drivers personal bookkeeping. | ||
762 | */ | ||
763 | count = 0; | ||
764 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
765 | save_crtcs[count++] = *crtc; | ||
766 | } | ||
767 | |||
768 | count = 0; | ||
769 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
770 | save_encoders[count++] = *encoder; | ||
771 | } | ||
772 | |||
773 | count = 0; | ||
774 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
775 | save_connectors[count++] = *connector; | ||
776 | } | ||
777 | |||
757 | /* We should be able to check here if the fb has the same properties | 778 | /* We should be able to check here if the fb has the same properties |
758 | * and then just flip_or_move it */ | 779 | * and then just flip_or_move it */ |
759 | if (set->crtc->fb != set->fb) { | 780 | if (set->crtc->fb != set->fb) { |
@@ -786,7 +807,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
786 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 807 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
787 | struct drm_connector_helper_funcs *connector_funcs = | 808 | struct drm_connector_helper_funcs *connector_funcs = |
788 | connector->helper_private; | 809 | connector->helper_private; |
789 | save_encoders[count++] = connector->encoder; | ||
790 | new_encoder = connector->encoder; | 810 | new_encoder = connector->encoder; |
791 | for (ro = 0; ro < set->num_connectors; ro++) { | 811 | for (ro = 0; ro < set->num_connectors; ro++) { |
792 | if (set->connectors[ro] == connector) { | 812 | if (set->connectors[ro] == connector) { |
@@ -809,7 +829,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
809 | 829 | ||
810 | if (fail) { | 830 | if (fail) { |
811 | ret = -EINVAL; | 831 | ret = -EINVAL; |
812 | goto fail_no_encoder; | 832 | goto fail; |
813 | } | 833 | } |
814 | 834 | ||
815 | count = 0; | 835 | count = 0; |
@@ -817,8 +837,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
817 | if (!connector->encoder) | 837 | if (!connector->encoder) |
818 | continue; | 838 | continue; |
819 | 839 | ||
820 | save_crtcs[count++] = connector->encoder->crtc; | ||
821 | |||
822 | if (connector->encoder->crtc == set->crtc) | 840 | if (connector->encoder->crtc == set->crtc) |
823 | new_crtc = NULL; | 841 | new_crtc = NULL; |
824 | else | 842 | else |
@@ -833,7 +851,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
833 | if (new_crtc && | 851 | if (new_crtc && |
834 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { | 852 | !drm_encoder_crtc_ok(connector->encoder, new_crtc)) { |
835 | ret = -EINVAL; | 853 | ret = -EINVAL; |
836 | goto fail_set_mode; | 854 | goto fail; |
837 | } | 855 | } |
838 | if (new_crtc != connector->encoder->crtc) { | 856 | if (new_crtc != connector->encoder->crtc) { |
839 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); | 857 | DRM_DEBUG_KMS("crtc changed, full mode switch\n"); |
@@ -862,7 +880,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
862 | DRM_ERROR("failed to set mode on crtc %p\n", | 880 | DRM_ERROR("failed to set mode on crtc %p\n", |
863 | set->crtc); | 881 | set->crtc); |
864 | ret = -EINVAL; | 882 | ret = -EINVAL; |
865 | goto fail_set_mode; | 883 | goto fail; |
866 | } | 884 | } |
867 | /* TODO are these needed? */ | 885 | /* TODO are these needed? */ |
868 | set->crtc->desired_x = set->x; | 886 | set->crtc->desired_x = set->x; |
@@ -877,30 +895,34 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | |||
877 | ret = crtc_funcs->mode_set_base(set->crtc, | 895 | ret = crtc_funcs->mode_set_base(set->crtc, |
878 | set->x, set->y, old_fb); | 896 | set->x, set->y, old_fb); |
879 | if (ret != 0) | 897 | if (ret != 0) |
880 | goto fail_set_mode; | 898 | goto fail; |
881 | } | 899 | } |
882 | 900 | ||
901 | kfree(save_connectors); | ||
883 | kfree(save_encoders); | 902 | kfree(save_encoders); |
884 | kfree(save_crtcs); | 903 | kfree(save_crtcs); |
885 | return 0; | 904 | return 0; |
886 | 905 | ||
887 | fail_set_mode: | 906 | fail: |
888 | set->crtc->enabled = save_enabled; | 907 | /* Restore all previous data. */ |
889 | set->crtc->fb = old_fb; | ||
890 | count = 0; | 908 | count = 0; |
891 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 909 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
892 | if (!connector->encoder) | 910 | *crtc = save_crtcs[count++]; |
893 | continue; | 911 | } |
894 | 912 | ||
895 | connector->encoder->crtc = save_crtcs[count++]; | 913 | count = 0; |
914 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
915 | *encoder = save_encoders[count++]; | ||
896 | } | 916 | } |
897 | fail_no_encoder: | 917 | |
898 | kfree(save_crtcs); | ||
899 | count = 0; | 918 | count = 0; |
900 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 919 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
901 | connector->encoder = save_encoders[count++]; | 920 | *connector = save_connectors[count++]; |
902 | } | 921 | } |
922 | |||
923 | kfree(save_connectors); | ||
903 | kfree(save_encoders); | 924 | kfree(save_encoders); |
925 | kfree(save_crtcs); | ||
904 | return ret; | 926 | return ret; |
905 | } | 927 | } |
906 | EXPORT_SYMBOL(drm_crtc_helper_set_config); | 928 | EXPORT_SYMBOL(drm_crtc_helper_set_config); |