From patchwork Mon Sep 10 03:03:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 11265 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 5FFED23E00 for ; Mon, 10 Sep 2012 03:06:05 +0000 (UTC) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by fiordland.canonical.com (Postfix) with ESMTP id 1682FA1870D for ; Mon, 10 Sep 2012 03:06:04 +0000 (UTC) Received: by mail-ie0-f180.google.com with SMTP id k11so2235201iea.11 for ; Sun, 09 Sep 2012 20:06:04 -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 :in-reply-to:references:x-gm-message-state; bh=hH+Dsoi+7OYMLvzCVagf1nRrq13FF+wkYtVEAOuBCqw=; b=VvG6gTW0i/oVLMfnHo71x8FlMoTJsFhff/Juuwi2RJj8m+OgF4ST15L2zP4Xbb1Hd1 gFCsE9MNtYFMneCcO5MAMBNLckHNt+O5HTCZwyHr7ta8zRbuiqQOmnOU9ZnTgBXUGt9j S5fivh2CMeeaddXkxW0g+778vZ6+m9WjMXIoqbVzSZL9bdzdzS/NZwqFHm/JxPGIEXB8 eJBM+k4KtdrZSg35kAp/U0pCFgTode5+3FweI1Xd67p+1LrRJSBIG0z6xgJzd6LrUMg/ QnkIZnH9qkdiLf1bndEpYj0kRYrmRnGYv9RjHami0yYGXqIEKTuBXzsWtL3jiLWtYAo0 u3Lg== Received: by 10.42.109.194 with SMTP id m2mr15307191icp.48.1347246364839; Sun, 09 Sep 2012 20:06:04 -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 ex8csp70837igc; Sun, 9 Sep 2012 20:06:04 -0700 (PDT) Received: by 10.60.25.131 with SMTP id c3mr12805084oeg.50.1347246364399; Sun, 09 Sep 2012 20:06:04 -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 is1si7284901obc.87.2012.09.09.20.06.04 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 09 Sep 2012 20:06:04 -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 mail-ob0-f178.google.com with SMTP id wd20so2865791obb.37 for ; Sun, 09 Sep 2012 20:06:04 -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:in-reply-to :references; bh=hH+Dsoi+7OYMLvzCVagf1nRrq13FF+wkYtVEAOuBCqw=; b=LosgZA2UVwroey45DZ8Oo10wyPnNelbE4p6L853JXY15rSyjQeD/TIQeig3d/dLlgp +W0NAWxk+r63xVCwVCJnU0jNE8Hv8OqsqPdyuU17167jBIeB4oqCdud2w9ZICLYD9x72 VpRBqBtojEVgUA4eHMJMvKuG4i5YRZ6dmVIg+TbLdM6jqcOf4aJZtSLpUg/FW0vCvn/Q fZnua70FmOvADJJVyASQKTidgbI/gcTMfnanNlezHCOSepMY8iWiQz840rP+EbiSpmHI fKzk0kx0DZxpD7DP0nMDYCzXhTDXPqAr5nkdXxHgidQER9h3vMKMM0P2FrPAlpmoqdLA XN9Q== Received: by 10.182.202.1 with SMTP id ke1mr12790837obc.51.1347246364240; Sun, 09 Sep 2012 20:06:04 -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 ec1sm12224179obc.2.2012.09.09.20.06.03 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 09 Sep 2012 20:06:03 -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 8/9] drm: nuclear pageflip Date: Sun, 9 Sep 2012 22:03:21 -0500 Message-Id: <1347246202-24249-9-git-send-email-rob.clark@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1347246202-24249-1-git-send-email-rob.clark@linaro.org> References: <1347246202-24249-1-git-send-email-rob.clark@linaro.org> X-Gm-Message-State: ALoCoQlddeiFT5I8Sxfzv7QcOinmPSHdqlEaTe4ijlujFQvwfi54r1cHX0y2LpY5Ys72PqpFTQM3 From: Rob Clark --- drivers/gpu/drm/drm_crtc.c | 147 +++++++++++++++++++++++++++++++++++--------- 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, 161 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0ddd43e..d285b11 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3792,6 +3792,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) { @@ -3800,7 +3845,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; @@ -3831,30 +3875,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(dev, obj, state, @@ -3863,15 +3888,79 @@ 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_nuclear_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_nuclear_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; + void *state; + int i, ret; + + if (page_flip->flags & ~DRM_MODE_NUCLEAR_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); + state = dev->driver->atomic_begin(dev); + 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 9238de4..d700042 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_MASTER|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_NUCLEAR_PAGE_FLIP, drm_mode_nuclear_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..dec69fd 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_NUCLEAR_PAGE_FLIP DRM_IOWR(0xBC, struct drm_mode_crtc_nuclear_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 9417aaa..9316fbf 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1080,6 +1080,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_nuclear_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 8cec2cf..32d6f65 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -408,7 +408,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_NUCLEAR_PAGE_FLIP_FLAGS \ + (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_TEST_ONLY) /* * Request a page flip on the specified crtc. @@ -440,6 +443,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_nuclear_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;