diff options
| -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 | ||
