From patchwork Thu Sep 13 04:00:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 11381 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 9404723F6B for ; Thu, 13 Sep 2012 04:00:29 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 81EC234B8F40 for ; Thu, 13 Sep 2012 04:00:28 +0000 (UTC) Received: by iafj25 with SMTP id j25so1824670iaf.11 for ; Wed, 12 Sep 2012 21:00:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :dkim-signature:sender:from:to:cc:subject:date:message-id:x-mailer :x-gm-message-state; bh=o44rYQmkkZc7DWq0siPqZ9jOcR+eRA8855AkMpmxl8Q=; b=j4ehgOxXLpJJ47v8qyQ0hwOJT6EhZONksb7cFCIxfpJ/o9fJ2vNMs7K0k7zdBQy4mm YFOpoIvLhfQuECYDSEOA7cxWYxPB8wWYFRELjTf4nv4MrC3pNimrlwn8Z+9YhCcvcRGx Av5u6tNZACoUlcgqZXkvBrLmwNU3p5Y5FlWOsIQzvzPc5z8k5BgGJ7MgBZMNAYiyOsnd HBH/iHEuX7QXT4PEaC/N+MsCTZO1zcoqs9NRvi8Qe+jwJPDd2JPDDftRPoAEnmc4cA0I xSMfRMrVcidww59ZmMc8FgDq0I+flUDKa7UgemLcKlQnwhjGYNkDg4j1aVqyv3r3bHFp 8rzQ== Received: by 10.50.207.106 with SMTP id lv10mr687479igc.0.1347508827863; Wed, 12 Sep 2012 21:00:27 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.184.232 with SMTP id ex8csp111441igc; Wed, 12 Sep 2012 21:00:27 -0700 (PDT) Received: by 10.60.169.138 with SMTP id ae10mr549573oec.7.1347508826596; Wed, 12 Sep 2012 21:00:26 -0700 (PDT) Received: from mail-ob0-f178.google.com (mail-ob0-f178.google.com [209.85.214.178]) by mx.google.com with ESMTPS id t3si28196328oet.32.2012.09.12.21.00.26 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 12 Sep 2012 21:00:26 -0700 (PDT) Received-SPF: pass (google.com: domain of robdclark@gmail.com designates 209.85.214.178 as permitted sender) client-ip=209.85.214.178; Authentication-Results: mx.google.com; spf=pass (google.com: domain of robdclark@gmail.com designates 209.85.214.178 as permitted sender) smtp.mail=robdclark@gmail.com; dkim=pass header.i=@gmail.com Received: by obbwd20 with SMTP id wd20so4608629obb.37 for ; Wed, 12 Sep 2012 21:00:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer; bh=o44rYQmkkZc7DWq0siPqZ9jOcR+eRA8855AkMpmxl8Q=; b=QnbN6ke2Lk7fDU8P1ILwQn5SCB3ILDpYSkuY5MURoPylL9vw0jAFvwZV6/xh1pa3mt PYtLuvP2mrxv7rLZcrn6iPbUh1ssKgJNhoZpvXKg/lHVFjuwGTvAxEczF80WwKi7lN6w vwmrgSGuLYNZl6w58QtgtShNe1VpEZ+6vaYPMMAo97jxr6B3b9qL5KkXvEsh/2isOhUd COiuoo0vcJ3b88UsCX2yr4thvhMhx/n9ZJa08Lz6NZd5r4mAOnTcco7WqZUVl3Rw7DuE CRSSwQemFe8M/WGQvoLVzGurWT2phjAhInbP06ILBKKFMpGyX0EEO9d70jxuO7HChcVt KXGw== Received: by 10.182.152.97 with SMTP id ux1mr540727obb.13.1347508825914; Wed, 12 Sep 2012 21:00:25 -0700 (PDT) Received: from localhost (ppp-70-129-131-42.dsl.rcsntx.swbell.net. [70.129.131.42]) by mx.google.com with ESMTPS id d6sm22561793obx.15.2012.09.12.21.00.24 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 12 Sep 2012 21:00:24 -0700 (PDT) Sender: Rob Clark From: Rob Clark To: dri-devel@lists.freedesktop.org Cc: patches@linaro.org, ville.syrjala@linux.intel.com, jbarnes@virtuousgeek.org, daniel.vetter@ffwll.ch, Rob Clark Subject: [RFC 10/11] drm: atomic pageflip Date: Wed, 12 Sep 2012 23:00:10 -0500 Message-Id: <1347508811-15029-1-git-send-email-rob.clark@linaro.org> X-Mailer: git-send-email 1.7.9.5 X-Gm-Message-State: ALoCoQlYwtpYR/buzFvM2YJ7eWaUZvlSHwuoJ9/vLinQufr89PJHM0F2Vt6XGklO1iTSDt70F2xF From: Rob Clark --- drivers/gpu/drm/drm_crtc.c | 157 ++++++++++++++++++++++++++++++++++++-------- drivers/gpu/drm/drm_drv.c | 1 + include/drm/drm.h | 2 + include/drm/drm_crtc.h | 2 + include/drm/drm_mode.h | 38 +++++++++++ 5 files changed, 171 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6d22c8c..7457d9a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3825,6 +3825,51 @@ out: return ret; } +static struct drm_pending_vblank_event *create_vblank_event( + struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) +{ + struct drm_pending_vblank_event *e = NULL; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (file_priv->event_space < sizeof e->event) { + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + file_priv->event_space -= sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (e == NULL) { + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof e->event; + e->event.user_data = user_data; + e->base.event = &e->event.base; + e->base.file_priv = file_priv; + e->base.destroy = + (void (*) (struct drm_pending_event *)) kfree; + +out: + return e; +} + +static void destroy_vblank_event(struct drm_device *dev, + struct drm_file *file_priv, struct drm_pending_vblank_event *e) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(e); +} + int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -3833,7 +3878,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_mode_object *obj; struct drm_crtc *crtc; struct drm_pending_vblank_event *e = NULL; - unsigned long flags; void *state; int ret = -EINVAL; @@ -3868,30 +3912,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, } if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { - ret = -ENOMEM; - spin_lock_irqsave(&dev->event_lock, flags); - if (file_priv->event_space < sizeof e->event) { - spin_unlock_irqrestore(&dev->event_lock, flags); - goto out; - } - file_priv->event_space -= sizeof e->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - - e = kzalloc(sizeof *e, GFP_KERNEL); - if (e == NULL) { - spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; - spin_unlock_irqrestore(&dev->event_lock, flags); + e = create_vblank_event(dev, file_priv, page_flip->user_data); + if (!e) { + ret = -ENOMEM; goto out; } - - e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof e->event; - e->event.user_data = page_flip->user_data; - e->base.event = &e->event.base; - e->base.file_priv = file_priv; - e->base.destroy = - (void (*) (struct drm_pending_event *)) kfree; } ret = drm_mode_set_obj_prop(obj, state, @@ -3900,15 +3925,89 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out; ret = dev->driver->atomic_commit(dev, state, e); - if (ret) { - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { - spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - kfree(e); + if (ret && e) + destroy_vblank_event(dev, file_priv, e); + +out: + dev->driver->atomic_end(dev, state); +out_unlock: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_atomic_page_flip *page_flip = data; + struct drm_mode_obj_set_property __user *props = + (struct drm_mode_obj_set_property __user *) + (unsigned long)page_flip->props_ptr; + struct drm_pending_vblank_event *e = NULL; + struct drm_mode_object *obj; + void *state; + int i, ret; + + if (page_flip->flags & ~DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS || + page_flip->reserved != 0) + return -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + mutex_lock(&dev->mode_config.mutex); + + obj = drm_mode_object_find(dev, page_flip->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_DEBUG_KMS("Unknown CRTC ID %d\n", page_flip->crtc_id); + ret = -ENOENT; + goto out_unlock; + } + + state = dev->driver->atomic_begin(dev, obj_to_crtc(obj)); + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto out_unlock; + } + + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { + e = create_vblank_event(dev, file_priv, page_flip->user_data); + if (!e) { + ret = -ENOMEM; + goto out; } } + for (i = 0; i < page_flip->count_props; i++) { + struct drm_mode_obj_set_property prop; + if (copy_from_user(&prop, &props[i], sizeof(prop))) { + ret = -EFAULT; + goto out; + } + + /* TODO should we enforce that none of the + * properties target objects in chain with + * other crtcs? Or just let the driver deal + * with it? + */ + + ret = drm_mode_set_obj_prop_id(dev, state, + prop.obj_id, prop.obj_type, + prop.prop_id, prop.value); + if (ret) + goto out; + } + + ret = dev->driver->atomic_check(dev, state); + if (ret) + goto out; + + if (!(page_flip->flags & DRM_MODE_TEST_ONLY)) + ret = dev->driver->atomic_commit(dev, state, e); + + if (ret && e) + destroy_vblank_event(dev, file_priv, e); + out: dev->driver->atomic_end(dev, state); out_unlock: diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 73e5633..933e7ae 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -166,6 +166,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP, drm_mode_atomic_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/include/drm/drm.h b/include/drm/drm.h index e51035a..0908741 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -732,6 +732,8 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) +/* placeholder for DRM_IOCTL_ATOMIC_MODE_SET */ +#define DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP DRM_IOWR(0xBC, struct drm_mode_crtc_atomic_page_flip) /** * Device specific ioctls should only be in their respective headers diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 92e6bf8..795ecee 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1117,6 +1117,8 @@ extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, bool reduced, bool interlaced, bool margins); diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 9cc0336..fdee5ed 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -410,7 +410,10 @@ struct drm_mode_crtc_lut { }; #define DRM_MODE_PAGE_FLIP_EVENT 0x01 +#define DRM_MODE_TEST_ONLY 0x02 #define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT +#define DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS \ + (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_TEST_ONLY) /* * Request a page flip on the specified crtc. @@ -442,6 +445,41 @@ struct drm_mode_crtc_page_flip { __u64 user_data; }; +/* + * Request a page flip on the crtc specified by 'crtc_id' plus zero or + * more planes attached to this crtc. + * + * This ioctl will ask KMS to schedule a page flip for the specified + * crtc. Once any pending rendering targeting the specified fb(s) (as + * of ioctl time) has completed, the crtc and zero or more planes will + * be reprogrammed to display the new fb(s) after the next vertical + * refresh. The ioctl returns immediately, but subsequent rendering + * to the current fb will block in the execbuffer ioctl until the page + * flip happens. If a page flip is already pending as the ioctl is + * called, EBUSY will be returned. + * + * The ioctl supports the following flags: + * + DRM_MODE_PAGE_FLIP_EVENT, which will request that drm sends back + * a vblank event (see drm.h: struct drm_event_vblank) when the page + * flip is done. The user_data field passed in with this ioctl will + * be returned as the user_data field in the vblank event struct. + * + DRM_MODE_TEST_ONLY, don't actually apply the changes (or generate + * a vblank event) but just test the configuration to see if it is + * possible. + * + * The reserved field must be zero until we figure out something clever + * to use it for. + */ + +struct drm_mode_crtc_atomic_page_flip { + uint32_t crtc_id; + uint32_t flags; + uint64_t user_data; + uint32_t reserved; + uint32_t count_props; + uint64_t props_ptr; /* ptr to array of drm_mode_obj_set_property */ +}; + /* create a dumb scanout buffer */ struct drm_mode_create_dumb { uint32_t height;