diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 44 |
1 files changed, 20 insertions, 24 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]) |