diff options
author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2016-02-17 02:32:05 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-02-18 22:24:03 -0500 |
commit | 5fff80bbdb6b84a94f90391ba674471d37b57eb2 (patch) | |
tree | f3f9520de7cb93de29c4b039c7b26f01acb8b65d | |
parent | 5441ea115ef153458b443917b02c7f5686cc2bd7 (diff) |
drm/atomic: Allow for holes in connector state, v2.
Because we record connector_mask using 1 << drm_connector_index now
the connector_mask should stay the same even when other connectors
are removed. This was not the case with MST, in that case when removing
a connector all other connectors may change their index.
This is fixed by waiting until the first get_connector_state to allocate
connector_state, and force reallocation when state is too small.
As a side effect connector arrays no longer have to be preallocated,
and can be allocated on first use which means a less allocations in
the page flip only path.
Changes since v1:
- Whitespace. (Ville)
- Call ida_remove when destroying the connector. (Ville)
- u32 alloc -> int. (Ville)
Fixes: 14de6c44d149 ("drm/atomic: Remove drm_atomic_connectors_for_crtc.")
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Lyude <cpaul@redhat.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 49 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 8 |
4 files changed, 48 insertions, 55 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3f74193885f1..9a7b44616b55 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -65,8 +65,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) | |||
65 | */ | 65 | */ |
66 | state->allow_modeset = true; | 66 | state->allow_modeset = true; |
67 | 67 | ||
68 | state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); | ||
69 | |||
70 | state->crtcs = kcalloc(dev->mode_config.num_crtc, | 68 | state->crtcs = kcalloc(dev->mode_config.num_crtc, |
71 | sizeof(*state->crtcs), GFP_KERNEL); | 69 | sizeof(*state->crtcs), GFP_KERNEL); |
72 | if (!state->crtcs) | 70 | if (!state->crtcs) |
@@ -83,16 +81,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) | |||
83 | sizeof(*state->plane_states), GFP_KERNEL); | 81 | sizeof(*state->plane_states), GFP_KERNEL); |
84 | if (!state->plane_states) | 82 | if (!state->plane_states) |
85 | goto fail; | 83 | goto fail; |
86 | state->connectors = kcalloc(state->num_connector, | ||
87 | sizeof(*state->connectors), | ||
88 | GFP_KERNEL); | ||
89 | if (!state->connectors) | ||
90 | goto fail; | ||
91 | state->connector_states = kcalloc(state->num_connector, | ||
92 | sizeof(*state->connector_states), | ||
93 | GFP_KERNEL); | ||
94 | if (!state->connector_states) | ||
95 | goto fail; | ||
96 | 84 | ||
97 | state->dev = dev; | 85 | state->dev = dev; |
98 | 86 | ||
@@ -823,19 +811,27 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, | |||
823 | 811 | ||
824 | index = drm_connector_index(connector); | 812 | index = drm_connector_index(connector); |
825 | 813 | ||
826 | /* | ||
827 | * Construction of atomic state updates can race with a connector | ||
828 | * hot-add which might overflow. In this case flip the table and just | ||
829 | * restart the entire ioctl - no one is fast enough to livelock a cpu | ||
830 | * with physical hotplug events anyway. | ||
831 | * | ||
832 | * Note that we only grab the indexes once we have the right lock to | ||
833 | * prevent hotplug/unplugging of connectors. So removal is no problem, | ||
834 | * at most the array is a bit too large. | ||
835 | */ | ||
836 | if (index >= state->num_connector) { | 814 | if (index >= state->num_connector) { |
837 | DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n"); | 815 | struct drm_connector **c; |
838 | return ERR_PTR(-EAGAIN); | 816 | struct drm_connector_state **cs; |
817 | int alloc = max(index + 1, config->num_connector); | ||
818 | |||
819 | c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL); | ||
820 | if (!c) | ||
821 | return ERR_PTR(-ENOMEM); | ||
822 | |||
823 | state->connectors = c; | ||
824 | memset(&state->connectors[state->num_connector], 0, | ||
825 | sizeof(*state->connectors) * (alloc - state->num_connector)); | ||
826 | |||
827 | cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL); | ||
828 | if (!cs) | ||
829 | return ERR_PTR(-ENOMEM); | ||
830 | |||
831 | state->connector_states = cs; | ||
832 | memset(&state->connector_states[state->num_connector], 0, | ||
833 | sizeof(*state->connector_states) * (alloc - state->num_connector)); | ||
834 | state->num_connector = alloc; | ||
839 | } | 835 | } |
840 | 836 | ||
841 | if (state->connector_states[index]) | 837 | if (state->connector_states[index]) |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7c523060a076..4f2d3e161593 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1493,7 +1493,7 @@ void drm_atomic_helper_swap_state(struct drm_device *dev, | |||
1493 | { | 1493 | { |
1494 | int i; | 1494 | int i; |
1495 | 1495 | ||
1496 | for (i = 0; i < dev->mode_config.num_connector; i++) { | 1496 | for (i = 0; i < state->num_connector; i++) { |
1497 | struct drm_connector *connector = state->connectors[i]; | 1497 | struct drm_connector *connector = state->connectors[i]; |
1498 | 1498 | ||
1499 | if (!connector) | 1499 | if (!connector) |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d40bab29747e..f6191215b2cb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -918,12 +918,19 @@ int drm_connector_init(struct drm_device *dev, | |||
918 | connector->base.properties = &connector->properties; | 918 | connector->base.properties = &connector->properties; |
919 | connector->dev = dev; | 919 | connector->dev = dev; |
920 | connector->funcs = funcs; | 920 | connector->funcs = funcs; |
921 | |||
922 | connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); | ||
923 | if (connector->connector_id < 0) { | ||
924 | ret = connector->connector_id; | ||
925 | goto out_put; | ||
926 | } | ||
927 | |||
921 | connector->connector_type = connector_type; | 928 | connector->connector_type = connector_type; |
922 | connector->connector_type_id = | 929 | connector->connector_type_id = |
923 | ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); | 930 | ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); |
924 | if (connector->connector_type_id < 0) { | 931 | if (connector->connector_type_id < 0) { |
925 | ret = connector->connector_type_id; | 932 | ret = connector->connector_type_id; |
926 | goto out_put; | 933 | goto out_put_id; |
927 | } | 934 | } |
928 | connector->name = | 935 | connector->name = |
929 | kasprintf(GFP_KERNEL, "%s-%d", | 936 | kasprintf(GFP_KERNEL, "%s-%d", |
@@ -931,7 +938,7 @@ int drm_connector_init(struct drm_device *dev, | |||
931 | connector->connector_type_id); | 938 | connector->connector_type_id); |
932 | if (!connector->name) { | 939 | if (!connector->name) { |
933 | ret = -ENOMEM; | 940 | ret = -ENOMEM; |
934 | goto out_put; | 941 | goto out_put_type_id; |
935 | } | 942 | } |
936 | 943 | ||
937 | INIT_LIST_HEAD(&connector->probed_modes); | 944 | INIT_LIST_HEAD(&connector->probed_modes); |
@@ -959,7 +966,12 @@ int drm_connector_init(struct drm_device *dev, | |||
959 | } | 966 | } |
960 | 967 | ||
961 | connector->debugfs_entry = NULL; | 968 | connector->debugfs_entry = NULL; |
962 | 969 | out_put_type_id: | |
970 | if (ret) | ||
971 | ida_remove(connector_ida, connector->connector_type_id); | ||
972 | out_put_id: | ||
973 | if (ret) | ||
974 | ida_remove(&config->connector_ida, connector->connector_id); | ||
963 | out_put: | 975 | out_put: |
964 | if (ret) | 976 | if (ret) |
965 | drm_mode_object_put(dev, &connector->base); | 977 | drm_mode_object_put(dev, &connector->base); |
@@ -996,6 +1008,9 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
996 | ida_remove(&drm_connector_enum_list[connector->connector_type].ida, | 1008 | ida_remove(&drm_connector_enum_list[connector->connector_type].ida, |
997 | connector->connector_type_id); | 1009 | connector->connector_type_id); |
998 | 1010 | ||
1011 | ida_remove(&dev->mode_config.connector_ida, | ||
1012 | connector->connector_id); | ||
1013 | |||
999 | kfree(connector->display_info.bus_formats); | 1014 | kfree(connector->display_info.bus_formats); |
1000 | drm_mode_object_put(dev, &connector->base); | 1015 | drm_mode_object_put(dev, &connector->base); |
1001 | kfree(connector->name); | 1016 | kfree(connector->name); |
@@ -1013,32 +1028,6 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
1013 | EXPORT_SYMBOL(drm_connector_cleanup); | 1028 | EXPORT_SYMBOL(drm_connector_cleanup); |
1014 | 1029 | ||
1015 | /** | 1030 | /** |
1016 | * drm_connector_index - find the index of a registered connector | ||
1017 | * @connector: connector to find index for | ||
1018 | * | ||
1019 | * Given a registered connector, return the index of that connector within a DRM | ||
1020 | * device's list of connectors. | ||
1021 | */ | ||
1022 | unsigned int drm_connector_index(struct drm_connector *connector) | ||
1023 | { | ||
1024 | unsigned int index = 0; | ||
1025 | struct drm_connector *tmp; | ||
1026 | struct drm_mode_config *config = &connector->dev->mode_config; | ||
1027 | |||
1028 | WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); | ||
1029 | |||
1030 | drm_for_each_connector(tmp, connector->dev) { | ||
1031 | if (tmp == connector) | ||
1032 | return index; | ||
1033 | |||
1034 | index++; | ||
1035 | } | ||
1036 | |||
1037 | BUG(); | ||
1038 | } | ||
1039 | EXPORT_SYMBOL(drm_connector_index); | ||
1040 | |||
1041 | /** | ||
1042 | * drm_connector_register - register a connector | 1031 | * drm_connector_register - register a connector |
1043 | * @connector: the connector to register | 1032 | * @connector: the connector to register |
1044 | * | 1033 | * |
@@ -5789,6 +5778,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
5789 | INIT_LIST_HEAD(&dev->mode_config.plane_list); | 5778 | INIT_LIST_HEAD(&dev->mode_config.plane_list); |
5790 | idr_init(&dev->mode_config.crtc_idr); | 5779 | idr_init(&dev->mode_config.crtc_idr); |
5791 | idr_init(&dev->mode_config.tile_idr); | 5780 | idr_init(&dev->mode_config.tile_idr); |
5781 | ida_init(&dev->mode_config.connector_ida); | ||
5792 | 5782 | ||
5793 | drm_modeset_lock_all(dev); | 5783 | drm_modeset_lock_all(dev); |
5794 | drm_mode_create_standard_properties(dev); | 5784 | drm_mode_create_standard_properties(dev); |
@@ -5869,6 +5859,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
5869 | crtc->funcs->destroy(crtc); | 5859 | crtc->funcs->destroy(crtc); |
5870 | } | 5860 | } |
5871 | 5861 | ||
5862 | ida_destroy(&dev->mode_config.connector_ida); | ||
5872 | idr_destroy(&dev->mode_config.tile_idr); | 5863 | idr_destroy(&dev->mode_config.tile_idr); |
5873 | idr_destroy(&dev->mode_config.crtc_idr); | 5864 | idr_destroy(&dev->mode_config.crtc_idr); |
5874 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); | 5865 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c65a212db77e..c5b4b81a831b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -1166,6 +1166,7 @@ struct drm_connector { | |||
1166 | struct drm_mode_object base; | 1166 | struct drm_mode_object base; |
1167 | 1167 | ||
1168 | char *name; | 1168 | char *name; |
1169 | int connector_id; | ||
1169 | int connector_type; | 1170 | int connector_type; |
1170 | int connector_type_id; | 1171 | int connector_type_id; |
1171 | bool interlace_allowed; | 1172 | bool interlace_allowed; |
@@ -2047,6 +2048,7 @@ struct drm_mode_config { | |||
2047 | struct list_head fb_list; | 2048 | struct list_head fb_list; |
2048 | 2049 | ||
2049 | int num_connector; | 2050 | int num_connector; |
2051 | struct ida connector_ida; | ||
2050 | struct list_head connector_list; | 2052 | struct list_head connector_list; |
2051 | int num_encoder; | 2053 | int num_encoder; |
2052 | struct list_head encoder_list; | 2054 | struct list_head encoder_list; |
@@ -2200,7 +2202,11 @@ int drm_connector_register(struct drm_connector *connector); | |||
2200 | void drm_connector_unregister(struct drm_connector *connector); | 2202 | void drm_connector_unregister(struct drm_connector *connector); |
2201 | 2203 | ||
2202 | extern void drm_connector_cleanup(struct drm_connector *connector); | 2204 | extern void drm_connector_cleanup(struct drm_connector *connector); |
2203 | extern unsigned int drm_connector_index(struct drm_connector *connector); | 2205 | static inline unsigned drm_connector_index(struct drm_connector *connector) |
2206 | { | ||
2207 | return connector->connector_id; | ||
2208 | } | ||
2209 | |||
2204 | /* helper to unplug all connectors from sysfs for device */ | 2210 | /* helper to unplug all connectors from sysfs for device */ |
2205 | extern void drm_connector_unplug_all(struct drm_device *dev); | 2211 | extern void drm_connector_unplug_all(struct drm_device *dev); |
2206 | 2212 | ||