From patchwork Wed Nov 19 19:47:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Zanoni X-Patchwork-Id: 5340701 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B9F859F7DE for ; Wed, 19 Nov 2014 19:48:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 733452021F for ; Wed, 19 Nov 2014 19:48:29 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2E7B72020E for ; Wed, 19 Nov 2014 19:48:28 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B551F6F164; Wed, 19 Nov 2014 11:48:26 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-qc0-f181.google.com (mail-qc0-f181.google.com [209.85.216.181]) by gabe.freedesktop.org (Postfix) with ESMTP id B0A156F15C; Wed, 19 Nov 2014 11:48:24 -0800 (PST) Received: by mail-qc0-f181.google.com with SMTP id m20so1035358qcx.12 for ; Wed, 19 Nov 2014 11:48:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5VzBibldioBYbJxh51JP/KXmFuq4FqmN3oFJs61+v7w=; b=PAuUrFmvpwO2qyxc8pOGZD6TcyjuQF9TGJnyNB2GvhfEw/PitLNvl5XXICY3b5tBdM JXDoFtGanYG2agdXGNg7EE8Muhji1u3qlajnekW20vQba2gse3Hx0bXDcvYSCGJASgaM 87g5FoynzOvvIOSimesJT/fzulByL0vGtpp4qBCH1aUHPvfJ0puuf08HKRjBVoBgekPi TynEcQcFIhWEEilJoeWKaQh7E2S0eDPNADwhwpvr5/0qZEmWziXIslYTB+DsyYQiGRxF l5DwoV8UUN5F0KY5eTxcieVdHHzRxgcpM84qSxR21YvScl8z5jHVmX7rs1mniCquiMbn GxCg== X-Received: by 10.224.98.148 with SMTP id q20mr50425818qan.18.1416426504284; Wed, 19 Nov 2014 11:48:24 -0800 (PST) Received: from localhost.localdomain ([177.96.119.122]) by mx.google.com with ESMTPSA id b60sm168806qge.22.2014.11.19.11.48.22 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 19 Nov 2014 11:48:23 -0800 (PST) From: Paulo Zanoni To: dri-devel@lists.freedesktop.org Subject: [RFC 1/7] drm: allow the drivers to call the vblank IOCTL internally Date: Wed, 19 Nov 2014 17:47:09 -0200 Message-Id: <1416426435-2237-3-git-send-email-przanoni@gmail.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1416426435-2237-1-git-send-email-przanoni@gmail.com> References: <1416426435-2237-1-git-send-email-przanoni@gmail.com> Cc: intel-gfx@lists.freedesktop.org, Paulo Zanoni X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Paulo Zanoni The i915.ko driver needs a way to schedule certain functions to run after some amount of vblanks. There are many different pieces of the driver which could benefit from that. Since what we want is essentially the vblank ioctl, this patch does the minimum change required to allow this ioctl to be called internally. The noticeable thing here is that the drivers pass a callback function, which is called by drm.ko after the specified amount of vblanks passes. The great benefit of this minimal change is that all the code responsible for taking care of properly emptying the queues (e.g., when the CRTC is disabled) is already there, so we don't need to rewrite it. The current wait vblank IOCTL is now implemented on top of these changes, and it provides its own callback: send_vblank_event(). Signed-off-by: Paulo Zanoni --- drivers/gpu/drm/drm_ioctl.c | 2 +- drivers/gpu/drm/drm_irq.c | 65 +++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_debugfs.c | 62 +++++++++++++++++++++++++++++++++++ include/drm/drmP.h | 13 ++++++-- 4 files changed, 125 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 00587a1..fb35173 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -578,7 +578,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0e47df4..f031f77 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -882,7 +882,8 @@ EXPORT_SYMBOL(drm_vblank_count_and_time); static void send_vblank_event(struct drm_device *dev, struct drm_pending_vblank_event *e, - unsigned long seq, struct timeval *now) + unsigned long seq, struct timeval *now, + bool premature) { WARN_ON_SMP(!spin_is_locked(&dev->event_lock)); e->event.sequence = seq; @@ -918,7 +919,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, now = get_drm_timestamp(); } e->pipe = crtc; - send_vblank_event(dev, e, seq, &now); + send_vblank_event(dev, e, seq, &now, false); } EXPORT_SYMBOL(drm_send_vblank_event); @@ -1159,7 +1160,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) e->event.sequence, seq); list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - send_vblank_event(dev, e, seq, &now); + e->callback(dev, e, seq, &now, true); } spin_unlock_irqrestore(&dev->event_lock, irqflags); } @@ -1373,7 +1374,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, static int drm_queue_vblank_event(struct drm_device *dev, int pipe, union drm_wait_vblank *vblwait, - struct drm_file *file_priv) + struct drm_file *file_priv, + drm_vblank_callback_t callback) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e; @@ -1396,6 +1398,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->base.event = &e->event.base; e->base.file_priv = file_priv; e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; + e->callback = callback; spin_lock_irqsave(&dev->event_lock, flags); @@ -1411,12 +1414,15 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, goto err_unlock; } - if (file_priv->event_space < sizeof e->event) { - ret = -EBUSY; - goto err_unlock; + if (file_priv) { + if (file_priv->event_space < sizeof e->event) { + ret = -EBUSY; + goto err_unlock; + } + + file_priv->event_space -= sizeof e->event; } - file_priv->event_space -= sizeof e->event; seq = drm_vblank_count_and_time(dev, pipe, &now); if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && @@ -1434,7 +1440,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { drm_vblank_put(dev, pipe); - send_vblank_event(dev, e, seq, &now); + e->callback(dev, e, seq, &now, false); vblwait->reply.sequence = seq; } else { /* drm_handle_vblank_events will call drm_vblank_put */ @@ -1468,11 +1474,12 @@ err_put: * the vblank interrupt refcount afterwards. (vblank IRQ disable follows that * after a timeout with no further vblank waits scheduled). */ -int drm_wait_vblank(struct drm_device *dev, void *data, - struct drm_file *file_priv) +static int __drm_wait_vblank(struct drm_device *dev, + union drm_wait_vblank *vblwait, + struct drm_file *file_priv, + drm_vblank_callback_t callback) { struct drm_vblank_crtc *vblank; - union drm_wait_vblank *vblwait = data; int ret; unsigned int flags, seq, crtc, high_crtc; @@ -1525,7 +1532,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, /* must hold on to the vblank ref until the event fires * drm_vblank_put will be called asynchronously */ - return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); + return drm_queue_vblank_event(dev, crtc, vblwait, file_priv, + callback); } if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -1560,6 +1568,35 @@ done: return ret; } +int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_wait_vblank *vblwait = data; + + return __drm_wait_vblank(dev, vblwait, file_priv, send_vblank_event); +} + +int drm_wait_vblank_kernel(struct drm_crtc *crtc, int count, bool absolute, + drm_vblank_callback_t callback, + unsigned long user_data) +{ + struct drm_device *dev = crtc->dev; + union drm_wait_vblank vblwait; + int type = 0; + + type |= absolute ? _DRM_VBLANK_ABSOLUTE : _DRM_VBLANK_RELATIVE; + type |= drm_crtc_index(crtc) << _DRM_VBLANK_HIGH_CRTC_SHIFT; + if (callback) + type |= _DRM_VBLANK_EVENT; + + vblwait.request.type = type; + vblwait.request.sequence = count; + vblwait.request.signal = user_data; + + return __drm_wait_vblank(dev, &vblwait, NULL, callback); +} +EXPORT_SYMBOL(drm_wait_vblank_kernel); + static void drm_handle_vblank_events(struct drm_device *dev, int crtc) { struct drm_pending_vblank_event *e, *t; @@ -1581,7 +1618,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - send_vblank_event(dev, e, seq, &now); + e->callback(dev, e, seq, &now, false); } trace_drm_vblank_event(crtc, seq); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 319da61..f989587 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2715,6 +2715,67 @@ static int i915_ddb_info(struct seq_file *m, void *unused) return 0; } +struct vblank_data { + int eight; + const char *message; +}; + +static void vblank_callback(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now, + bool premature) +{ + struct vblank_data *data = (struct vblank_data *)e->event.user_data; + + WARN_ON(data->eight != 8); + DRM_DEBUG_KMS("vblank callback, seq: %lu, premature: %s message:%s\n", + seq, yesno(premature), data->message); + + e->base.destroy(&e->base); + kfree(data); +} + +static int i915_vblank_queue_test_new(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct intel_crtc *crtc = NULL; + int ret = 0; + struct vblank_data *data; + + for_each_intel_crtc(dev, crtc) + if (crtc->pipe == PIPE_A) + break; + if (WARN_ON(!crtc)) + return -EINVAL; + + data = kzalloc(sizeof *data, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->message = "hello world"; + data->eight = 8; + + DRM_DEBUG_KMS("waiting 60 vblanks (no callback)\n"); + ret = drm_wait_vblank_kernel(&crtc->base, 60, false, NULL, 0); + if (ret) { + DRM_DEBUG_KMS("vblank wait error: %d\n", ret); + return ret; + } + DRM_DEBUG_KMS("vblank wait done\n"); + + DRM_DEBUG_KMS("scheduling 60 vblanks (with callback)\n"); + ret = drm_wait_vblank_kernel(&crtc->base, 60, false, vblank_callback, + (unsigned long) data); + if (ret) { + DRM_DEBUG_KMS("vblank schedule error: %d\n", ret); + return ret; + } + DRM_DEBUG_KMS("vblanks scheduled\n"); + + return 0; +} + struct pipe_crc_info { const char *name; struct drm_device *dev; @@ -4289,6 +4350,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_wa_registers", i915_wa_registers, 0}, {"i915_ddb_info", i915_ddb_info, 0}, + {"i915_vblank_queue_test_new", i915_vblank_queue_test_new, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index be776fb..39d0d87 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -660,11 +660,16 @@ struct drm_minor { struct drm_mode_group mode_group; }; +typedef void (*drm_vblank_callback_t)(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now, + bool premature); struct drm_pending_vblank_event { struct drm_pending_event base; int pipe; struct drm_event_vblank event; + drm_vblank_callback_t callback; }; struct drm_vblank_crtc { @@ -898,8 +903,12 @@ extern int drm_irq_install(struct drm_device *dev, int irq); extern int drm_irq_uninstall(struct drm_device *dev); extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); -extern int drm_wait_vblank(struct drm_device *dev, void *data, - struct drm_file *filp); +extern int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +extern int drm_wait_vblank_kernel(struct drm_crtc *crtc, int count, + bool absolute, + drm_vblank_callback_t callback, + unsigned long user_data); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime);