aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-02 07:48:21 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-01-20 16:16:55 -0500
commitbfb899282f500eeb9dff2600729904aad0fd39e7 (patch)
tree817752a33cd9ddb8d789e1a4318a7fad080d9676
parent29494c174dc4793ebd236aa522a2a1ed73b7180e (diff)
drm: only take the crtc lock for ->cursor_set
First convert ->cursor_set to only take the crtc lock, since that seems to be the function with the least amount of state - the core ioctl function doesn't check anything which can change at runtime, so we don't have any object lifetime issues to contend. The only thing which is important is that the driver's implementation doesn't touch any state outside of that single crtc which is not yet properly protected by other locking: - ast: access the global ast->cache_kmap. Luckily we only have on crtc on this driver, so this is fine. Add a comment. - gma500: calls gma_power_begin|and and psb_gtt_pin|unpin, both which have their own locking to protect their state. Everything else is crtc-local. - i915: touches a bit of global gem state, all protected by the One Lock to Rule Them All (dev->struct_mutex). - nouveau: Pre-nv50 is all nice, nv50+ uses the evo channels to queue up all display changes. And some of these channels are device global. But this is fine now since the previous patch introduced an evo channel mutex. - radeon: Uses some indirect register access for cursor updates, but with the previous patches to protect these indirect 2-register access patterns with a spinlock, this should be fine now, too. - vmwgfx: I have no idea how that works - update_cursor_position doesn't take any per-crtc argument and I haven't figured out any other place where this could be set in some form of a side-channel. But vmwgfx definitely has more than one crtc (or at least can register more than one), so I have no idea how this is supposed to not fail with the current code already. Hence take the easy way out and simply acquire all locks (which requires dropping the crtc lock the core acquired for us). That way it's not worse off for consistency than the old code. Reviewed-by: Rob Clark <rob@ti.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h2
-rw-r--r--drivers/gpu/drm/drm_crtc.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c32
3 files changed, 32 insertions, 8 deletions
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 5ccf984f063a..528429252f0f 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -98,6 +98,8 @@ struct ast_private {
98 98
99 struct drm_gem_object *cursor_cache; 99 struct drm_gem_object *cursor_cache;
100 uint64_t cursor_cache_gpu_addr; 100 uint64_t cursor_cache_gpu_addr;
101 /* Acces to this cache is protected by the crtc->mutex of the only crtc
102 * we have. */
101 struct ttm_bo_kmap_obj cache_kmap; 103 struct ttm_bo_kmap_obj cache_kmap;
102 int next_cursor; 104 int next_cursor;
103}; 105};
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b7c6168fae7e..58fa69e5ff4c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2036,7 +2036,6 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
2036 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2036 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
2037 return -EINVAL; 2037 return -EINVAL;
2038 2038
2039 drm_modeset_lock_all(dev);
2040 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); 2039 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
2041 if (!obj) { 2040 if (!obj) {
2042 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2041 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
@@ -2051,20 +2050,23 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
2051 goto out; 2050 goto out;
2052 } 2051 }
2053 /* Turns off the cursor if handle is 0 */ 2052 /* Turns off the cursor if handle is 0 */
2053 mutex_lock(&crtc->mutex);
2054 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2054 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2055 req->width, req->height); 2055 req->width, req->height);
2056 mutex_unlock(&crtc->mutex);
2056 } 2057 }
2057 2058
2058 if (req->flags & DRM_MODE_CURSOR_MOVE) { 2059 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2059 if (crtc->funcs->cursor_move) { 2060 if (crtc->funcs->cursor_move) {
2061 drm_modeset_lock_all(dev);
2060 ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2062 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2063 drm_modeset_unlock_all(dev);
2061 } else { 2064 } else {
2062 ret = -EFAULT; 2065 ret = -EFAULT;
2063 goto out; 2066 goto out;
2064 } 2067 }
2065 } 2068 }
2066out: 2069out:
2067 drm_modeset_unlock_all(dev);
2068 return ret; 2070 return ret;
2069} 2071}
2070 2072
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 9c0876b908ae..8d82e631c305 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -180,16 +180,29 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
180 struct vmw_dma_buffer *dmabuf = NULL; 180 struct vmw_dma_buffer *dmabuf = NULL;
181 int ret; 181 int ret;
182 182
183 /*
184 * FIXME: Unclear whether there's any global state touched by the
185 * cursor_set function, especially vmw_cursor_update_position looks
186 * suspicious. For now take the easy route and reacquire all locks. We
187 * can do this since the caller in the drm core doesn't check anything
188 * which is protected by any looks.
189 */
190 mutex_unlock(&crtc->mutex);
191 drm_modeset_lock_all(dev_priv->dev);
192
183 /* A lot of the code assumes this */ 193 /* A lot of the code assumes this */
184 if (handle && (width != 64 || height != 64)) 194 if (handle && (width != 64 || height != 64)) {
185 return -EINVAL; 195 ret = -EINVAL;
196 goto out;
197 }
186 198
187 if (handle) { 199 if (handle) {
188 ret = vmw_user_lookup_handle(dev_priv, tfile, 200 ret = vmw_user_lookup_handle(dev_priv, tfile,
189 handle, &surface, &dmabuf); 201 handle, &surface, &dmabuf);
190 if (ret) { 202 if (ret) {
191 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); 203 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
192 return -EINVAL; 204 ret = -EINVAL;
205 goto out;
193 } 206 }
194 } 207 }
195 208
@@ -197,7 +210,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
197 if (surface && !surface->snooper.image) { 210 if (surface && !surface->snooper.image) {
198 DRM_ERROR("surface not suitable for cursor\n"); 211 DRM_ERROR("surface not suitable for cursor\n");
199 vmw_surface_unreference(&surface); 212 vmw_surface_unreference(&surface);
200 return -EINVAL; 213 ret = -EINVAL;
214 goto out;
201 } 215 }
202 216
203 /* takedown old cursor */ 217 /* takedown old cursor */
@@ -225,14 +239,20 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
225 du->hotspot_x, du->hotspot_y); 239 du->hotspot_x, du->hotspot_y);
226 } else { 240 } else {
227 vmw_cursor_update_position(dev_priv, false, 0, 0); 241 vmw_cursor_update_position(dev_priv, false, 0, 0);
228 return 0; 242 ret = 0;
243 goto out;
229 } 244 }
230 245
231 vmw_cursor_update_position(dev_priv, true, 246 vmw_cursor_update_position(dev_priv, true,
232 du->cursor_x + du->hotspot_x, 247 du->cursor_x + du->hotspot_x,
233 du->cursor_y + du->hotspot_y); 248 du->cursor_y + du->hotspot_y);
234 249
235 return 0; 250 ret = 0;
251out:
252 drm_modeset_unlock_all(dev_priv->dev);
253 mutex_lock(&crtc->mutex);
254
255 return ret;
236} 256}
237 257
238int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) 258int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)