aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2014-11-25 17:50:05 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-11-27 09:39:11 -0500
commitabd69c55dd8f1f71b33b8c6165217f4329db8f25 (patch)
tree7a3af2b73d2b9ccf4f625de8f4ade7c16115bda4
parent933f622fc25c7d14f8d435357f9146cfe58a5d7a (diff)
drm: Handle atomic state properly in kms getfoo ioctl
So the problem with async commit (especially async modeset commit) is that the legacy pointers only get updated after the point of no return, in the async part of the modeset sequence. At least as implemented by the current helper functions. This is done in the set_routing_links function in drm_atomic_helper.c. Which also means that access isn't protected by locks but only coordinated by synchronizing with async workers. No problem thus far, until we lock at the getconnector/encoder ioctls. So fix this up by adding special cases for atomic drivers: For those we need to look at state objects. Unfortunately digging out the correct encoder->crtc link is a bit of work, so wrap this up in a helper function. Moving the assignments of connector->encoder and encoder->crtc earlier isn't a good idea because the point of the atomic helpers is that we stage the state updates. That way the disable functions can still inspect the links and rely upon them. v2: Extract full encoder->crtc lookup into helper (Rob). v3: Extract drm_connector_get_encoder too since - we need to always return state->best_encoder when there is a state otherwise we might return stale data if there's a pending async disable (and chase unlocked pointers, too). Same issue with encoder_get_crtc but there it's a bit more tricky to handle. Cc: Rob Clark <robdclark@gmail.com> Cc: Sean Paul <seanpaul@chromium.org> Reviewed-by: Sean Paul <seanpaul@chromium.org> Lightly-Tested-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
-rw-r--r--drivers/gpu/drm/drm_crtc.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3fd85772afb8..de79283eaea7 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1968,6 +1968,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
1968 return true; 1968 return true;
1969} 1969}
1970 1970
1971static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
1972{
1973 /* For atomic drivers only state objects are synchronously updated and
1974 * protected by modeset locks, so check those first. */
1975 if (connector->state)
1976 return connector->state->best_encoder;
1977 return connector->encoder;
1978}
1979
1971/** 1980/**
1972 * drm_mode_getconnector - get connector configuration 1981 * drm_mode_getconnector - get connector configuration
1973 * @dev: drm device for the ioctl 1982 * @dev: drm device for the ioctl
@@ -1986,6 +1995,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1986{ 1995{
1987 struct drm_mode_get_connector *out_resp = data; 1996 struct drm_mode_get_connector *out_resp = data;
1988 struct drm_connector *connector; 1997 struct drm_connector *connector;
1998 struct drm_encoder *encoder;
1989 struct drm_display_mode *mode; 1999 struct drm_display_mode *mode;
1990 int mode_count = 0; 2000 int mode_count = 0;
1991 int props_count = 0; 2001 int props_count = 0;
@@ -2041,8 +2051,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
2041 out_resp->subpixel = connector->display_info.subpixel_order; 2051 out_resp->subpixel = connector->display_info.subpixel_order;
2042 out_resp->connection = connector->status; 2052 out_resp->connection = connector->status;
2043 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2053 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2044 if (connector->encoder) 2054
2045 out_resp->encoder_id = connector->encoder->base.id; 2055 encoder = drm_connector_get_encoder(connector);
2056 if (encoder)
2057 out_resp->encoder_id = encoder->base.id;
2046 else 2058 else
2047 out_resp->encoder_id = 0; 2059 out_resp->encoder_id = 0;
2048 drm_modeset_unlock(&dev->mode_config.connection_mutex); 2060 drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2112,6 +2124,33 @@ out:
2112 return ret; 2124 return ret;
2113} 2125}
2114 2126
2127static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
2128{
2129 struct drm_connector *connector;
2130 struct drm_device *dev = encoder->dev;
2131 bool uses_atomic = false;
2132
2133 /* For atomic drivers only state objects are synchronously updated and
2134 * protected by modeset locks, so check those first. */
2135 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2136 if (!connector->state)
2137 continue;
2138
2139 uses_atomic = true;
2140
2141 if (connector->state->best_encoder != encoder)
2142 continue;
2143
2144 return connector->state->crtc;
2145 }
2146
2147 /* Don't return stale data (e.g. pending async disable). */
2148 if (uses_atomic)
2149 return NULL;
2150
2151 return encoder->crtc;
2152}
2153
2115/** 2154/**
2116 * drm_mode_getencoder - get encoder configuration 2155 * drm_mode_getencoder - get encoder configuration
2117 * @dev: drm device for the ioctl 2156 * @dev: drm device for the ioctl
@@ -2130,6 +2169,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
2130{ 2169{
2131 struct drm_mode_get_encoder *enc_resp = data; 2170 struct drm_mode_get_encoder *enc_resp = data;
2132 struct drm_encoder *encoder; 2171 struct drm_encoder *encoder;
2172 struct drm_crtc *crtc;
2133 2173
2134 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2174 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2135 return -EINVAL; 2175 return -EINVAL;
@@ -2139,7 +2179,10 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
2139 return -ENOENT; 2179 return -ENOENT;
2140 2180
2141 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2181 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2142 if (encoder->crtc) 2182 crtc = drm_encoder_get_crtc(encoder);
2183 if (crtc)
2184 enc_resp->crtc_id = crtc->base.id;
2185 else if (encoder->crtc)
2143 enc_resp->crtc_id = encoder->crtc->base.id; 2186 enc_resp->crtc_id = encoder->crtc->base.id;
2144 else 2187 else
2145 enc_resp->crtc_id = 0; 2188 enc_resp->crtc_id = 0;