From 5fff80bbdb6b84a94f90391ba674471d37b57eb2 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Wed, 17 Feb 2016 08:32:05 +0100 Subject: drm/atomic: Allow for holes in connector state, v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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> --- drivers/gpu/drm/drm_atomic.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/drm_atomic.c') 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) */ state->allow_modeset = true; - state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); - state->crtcs = kcalloc(dev->mode_config.num_crtc, sizeof(*state->crtcs), GFP_KERNEL); if (!state->crtcs) @@ -83,16 +81,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) sizeof(*state->plane_states), GFP_KERNEL); if (!state->plane_states) goto fail; - state->connectors = kcalloc(state->num_connector, - sizeof(*state->connectors), - GFP_KERNEL); - if (!state->connectors) - goto fail; - state->connector_states = kcalloc(state->num_connector, - sizeof(*state->connector_states), - GFP_KERNEL); - if (!state->connector_states) - goto fail; state->dev = dev; @@ -823,19 +811,27 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, index = drm_connector_index(connector); - /* - * Construction of atomic state updates can race with a connector - * hot-add which might overflow. In this case flip the table and just - * restart the entire ioctl - no one is fast enough to livelock a cpu - * with physical hotplug events anyway. - * - * Note that we only grab the indexes once we have the right lock to - * prevent hotplug/unplugging of connectors. So removal is no problem, - * at most the array is a bit too large. - */ if (index >= state->num_connector) { - DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n"); - return ERR_PTR(-EAGAIN); + struct drm_connector **c; + struct drm_connector_state **cs; + int alloc = max(index + 1, config->num_connector); + + c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + state->connectors = c; + memset(&state->connectors[state->num_connector], 0, + sizeof(*state->connectors) * (alloc - state->num_connector)); + + cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL); + if (!cs) + return ERR_PTR(-ENOMEM); + + state->connector_states = cs; + memset(&state->connector_states[state->num_connector], 0, + sizeof(*state->connector_states) * (alloc - state->num_connector)); + state->num_connector = alloc; } if (state->connector_states[index]) -- cgit v1.2.3