aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorMatt Roper <matthew.d.roper@intel.com>2014-06-10 11:28:10 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-06-13 11:45:21 -0400
commit161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662 (patch)
treebeecacf8192a09a94e837a669770e783c9c3897f /drivers/gpu/drm/drm_crtc.c
parentb36552b32aa9c69e83a3a20bda56379fb9e52435 (diff)
drm: Support legacy cursor ioctls via universal planes when possible (v4)
If drivers support universal planes and have registered a cursor plane with the DRM core, we should use that universal plane support when handling legacy cursor ioctls. Drivers that transition to universal planes won't have to maintain separate legacy ioctl handling; drivers that don't transition to universal planes will continue to operate without any change to behavior. Note that there's a bit of a mismatch between the legacy cursor ioctls and the universal plane API's --- legacy ioctl's use driver buffer handles directly whereas the universal plane API takes drm_framebuffers. Since there's no way to recover the driver handle from a drm_framebuffer, we can implement legacy ioctl's in terms of universal plane interfaces, but cannot implement universal plane interfaces in terms of legacy ioctls. Specifically, there's no way to create a general cursor helper in the way we previously created a primary plane helper. It's important to land this patch before any patches that add universal cursor support to individual drivers so that drivers don't have to worry about juggling two different styles of reference counting for cursor buffers when userspace mixes and matches legacy and universal cursor calls. With this patch, a driver that switches to universal cursor support may assume that all cursor buffers are wrapped in a drm_framebuffer and can rely on framebuffer reference counting for all cursor operations. v4: - Add comments pointing out setplane_internal's reference-eating semantics. v3: - Drop drm_mode_rmfb() call that is no longer needed now that we're using setplane_internal(), which takes care of deref'ing the appropriate framebuffer. v2: - Use new add_framebuffer_internal() function to create framebuffer rather than trying to call directly into the ioctl interface and look up the handle returned. - Use new setplane_internal() function to update the cursor plane rather than calling through the ioctl interface. Note that since we're no longer looking up an fb_id, no extra reference will be taken here. - Grab extra reference to fb under lock in !BO case to avoid issues where racing userspace could cause the fb to be destroyed out from under us after we grab the fb pointer. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Pallavi G<pallavi.g@intel.com> Acked-by: Dave Airlie <airlied@linux.ie> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 27eae03bd38e..b5bce5b6bf61 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2288,6 +2288,10 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2288 crtc = obj_to_crtc(obj); 2288 crtc = obj_to_crtc(obj);
2289 } 2289 }
2290 2290
2291 /*
2292 * setplane_internal will take care of deref'ing either the old or new
2293 * framebuffer depending on success.
2294 */
2291 return setplane_internal(crtc, plane, fb, 2295 return setplane_internal(crtc, plane, fb,
2292 plane_req->crtc_x, plane_req->crtc_y, 2296 plane_req->crtc_x, plane_req->crtc_y,
2293 plane_req->crtc_w, plane_req->crtc_h, 2297 plane_req->crtc_w, plane_req->crtc_h,
@@ -2541,6 +2545,102 @@ out:
2541 return ret; 2545 return ret;
2542} 2546}
2543 2547
2548/**
2549 * drm_mode_cursor_universal - translate legacy cursor ioctl call into a
2550 * universal plane handler call
2551 * @crtc: crtc to update cursor for
2552 * @req: data pointer for the ioctl
2553 * @file_priv: drm file for the ioctl call
2554 *
2555 * Legacy cursor ioctl's work directly with driver buffer handles. To
2556 * translate legacy ioctl calls into universal plane handler calls, we need to
2557 * wrap the native buffer handle in a drm_framebuffer.
2558 *
2559 * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB
2560 * buffer with a pitch of 4*width; the universal plane interface should be used
2561 * directly in cases where the hardware can support other buffer settings and
2562 * userspace wants to make use of these capabilities.
2563 *
2564 * Returns:
2565 * Zero on success, errno on failure.
2566 */
2567static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2568 struct drm_mode_cursor2 *req,
2569 struct drm_file *file_priv)
2570{
2571 struct drm_device *dev = crtc->dev;
2572 struct drm_framebuffer *fb = NULL;
2573 struct drm_mode_fb_cmd2 fbreq = {
2574 .width = req->width,
2575 .height = req->height,
2576 .pixel_format = DRM_FORMAT_ARGB8888,
2577 .pitches = { req->width * 4 },
2578 .handles = { req->handle },
2579 };
2580 int32_t crtc_x, crtc_y;
2581 uint32_t crtc_w = 0, crtc_h = 0;
2582 uint32_t src_w = 0, src_h = 0;
2583 int ret = 0;
2584
2585 BUG_ON(!crtc->cursor);
2586
2587 /*
2588 * Obtain fb we'll be using (either new or existing) and take an extra
2589 * reference to it if fb != null. setplane will take care of dropping
2590 * the reference if the plane update fails.
2591 */
2592 if (req->flags & DRM_MODE_CURSOR_BO) {
2593 if (req->handle) {
2594 fb = add_framebuffer_internal(dev, &fbreq, file_priv);
2595 if (IS_ERR(fb)) {
2596 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
2597 return PTR_ERR(fb);
2598 }
2599
2600 drm_framebuffer_reference(fb);
2601 } else {
2602 fb = NULL;
2603 }
2604 } else {
2605 mutex_lock(&dev->mode_config.mutex);
2606 fb = crtc->cursor->fb;
2607 if (fb)
2608 drm_framebuffer_reference(fb);
2609 mutex_unlock(&dev->mode_config.mutex);
2610 }
2611
2612 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2613 crtc_x = req->x;
2614 crtc_y = req->y;
2615 } else {
2616 crtc_x = crtc->cursor_x;
2617 crtc_y = crtc->cursor_y;
2618 }
2619
2620 if (fb) {
2621 crtc_w = fb->width;
2622 crtc_h = fb->height;
2623 src_w = fb->width << 16;
2624 src_h = fb->height << 16;
2625 }
2626
2627 /*
2628 * setplane_internal will take care of deref'ing either the old or new
2629 * framebuffer depending on success.
2630 */
2631 ret = setplane_internal(crtc, crtc->cursor, fb,
2632 crtc_x, crtc_y, crtc_w, crtc_h,
2633 0, 0, src_w, src_h);
2634
2635 /* Update successful; save new cursor position, if necessary */
2636 if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
2637 crtc->cursor_x = req->x;
2638 crtc->cursor_y = req->y;
2639 }
2640
2641 return ret;
2642}
2643
2544static int drm_mode_cursor_common(struct drm_device *dev, 2644static int drm_mode_cursor_common(struct drm_device *dev,
2545 struct drm_mode_cursor2 *req, 2645 struct drm_mode_cursor2 *req,
2546 struct drm_file *file_priv) 2646 struct drm_file *file_priv)
@@ -2560,6 +2660,13 @@ static int drm_mode_cursor_common(struct drm_device *dev,
2560 return -ENOENT; 2660 return -ENOENT;
2561 } 2661 }
2562 2662
2663 /*
2664 * If this crtc has a universal cursor plane, call that plane's update
2665 * handler rather than using legacy cursor handlers.
2666 */
2667 if (crtc->cursor)
2668 return drm_mode_cursor_universal(crtc, req, file_priv);
2669
2563 drm_modeset_lock(&crtc->mutex, NULL); 2670 drm_modeset_lock(&crtc->mutex, NULL);
2564 if (req->flags & DRM_MODE_CURSOR_BO) { 2671 if (req->flags & DRM_MODE_CURSOR_BO) {
2565 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2672 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {