From patchwork Thu Jun 9 01:46:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dhinakaran Pandiyan X-Patchwork-Id: 9166107 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 40F5460467 for ; Thu, 9 Jun 2016 01:33:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3182326E1A for ; Thu, 9 Jun 2016 01:33:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 266E1281FE; Thu, 9 Jun 2016 01:33:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98B2D26E1A for ; Thu, 9 Jun 2016 01:33:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F3F836E302; Thu, 9 Jun 2016 01:33:37 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTP id E1B386E302 for ; Thu, 9 Jun 2016 01:33:35 +0000 (UTC) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP; 08 Jun 2016 18:33:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,442,1459839600"; d="scan'208";a="716193706" Received: from skylake.jf.intel.com ([10.54.75.142]) by FMSMGA003.fm.intel.com with ESMTP; 08 Jun 2016 18:33:35 -0700 From: Dhinakaran Pandiyan To: intel-gfx@lists.freedesktop.org Date: Wed, 8 Jun 2016 18:46:02 -0700 Message-Id: <1465436764-29950-2-git-send-email-dhinakaran.pandiyan@intel.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1465436764-29950-1-git-send-email-dhinakaran.pandiyan@intel.com> References: <1465436764-29950-1-git-send-email-dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi Subject: [Intel-gfx] [PATCH 1/3] drm: Add vblank prepare and unprepare hooks. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP From: Rodrigo Vivi This will allow drivers to control specific power saving feature and power domains when dealing with vblanks. Vblanks code are protected by spin_locks where we can't have anything that can sleep. While power saving features and power domain code have mutexes to control the states. Mutex can sleep so they cannot be used inside spin lock areas. So the easiest way to deal with them currently is to add these prepare hook for pre enabling vblanks and unprepare one for post disabling them. Let's introduce this optional prepare and unprepare hooks so drivers can deal with cases like this and any other case that should require sleeping codes interacting with vblanks. Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/drm_irq.c | 28 +++++++++++++++++++++++++++- include/drm/drmP.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index d3124b6..c833a5d 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -411,6 +411,8 @@ void drm_vblank_cleanup(struct drm_device *dev) drm_core_check_feature(dev, DRIVER_MODESET)); del_timer_sync(&vblank->disable_timer); + + flush_work(&vblank->unprepare.work); } kfree(dev->vblank); @@ -419,6 +421,20 @@ void drm_vblank_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_vblank_cleanup); +static void drm_vblank_unprepare_work_fn(struct work_struct *work) +{ + struct drm_vblank_crtc *vblank; + struct drm_device *dev; + + vblank = container_of(work, typeof(*vblank), unprepare.work); + dev = vblank->dev; + + do { + if (dev->driver->unprepare_vblank) + dev->driver->unprepare_vblank(dev, vblank->pipe); + } while (!atomic_dec_and_test(&vblank->unprepare.counter)); +} + /** * drm_vblank_init - initialize vblank support * @dev: DRM device @@ -451,6 +467,8 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) init_waitqueue_head(&vblank->queue); setup_timer(&vblank->disable_timer, vblank_disable_fn, (unsigned long)vblank); + INIT_WORK(&vblank->unprepare.work, + drm_vblank_unprepare_work_fn); } DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); @@ -1241,6 +1259,9 @@ int drm_vblank_get(struct drm_device *dev, unsigned int pipe) if (WARN_ON(pipe >= dev->num_crtcs)) return -EINVAL; + if (dev->driver->prepare_vblank) + dev->driver->prepare_vblank(dev, pipe); + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &vblank->refcount) == 1) { @@ -1253,6 +1274,9 @@ int drm_vblank_get(struct drm_device *dev, unsigned int pipe) } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + if (ret != 0 && dev->driver->unprepare_vblank) + dev->driver->unprepare_vblank(dev, pipe); + return ret; } EXPORT_SYMBOL(drm_vblank_get); @@ -1305,6 +1329,9 @@ void drm_vblank_put(struct drm_device *dev, unsigned int pipe) mod_timer(&vblank->disable_timer, jiffies + ((drm_vblank_offdelay * HZ)/1000)); } + + atomic_inc(&vblank->unprepare.counter); + schedule_work(&vblank->unprepare.work); } EXPORT_SYMBOL(drm_vblank_put); @@ -1740,7 +1767,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, } spin_unlock_irqrestore(&dev->event_lock, flags); - return 0; err_unlock: diff --git a/include/drm/drmP.h b/include/drm/drmP.h index ed89038..544c65f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -447,6 +447,30 @@ struct drm_driver { u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe); /** + * prepare_vblank - Optional prepare vblank hook. + * @dev: DRM device + * @pipe: counter to fetch + * + * Drivers that need to handle any kind of mutex or any other sleeping + * code in combination with vblanks need to implement this hook + * that will be called before drm_vblank_get spin_lock gets. + */ + void (*prepare_vblank) (struct drm_device *dev, unsigned int pipe); + + /** + * unprepare_vblank - Optional unprepare vblank hook. + * @dev: DRM device + * @pipe: counter to fetch + * + * Drivers that need to handle any kind of mutex or any other sleeping + * code in combination with vblanks need to implement this hook + * that will be called in a work queue to be executed after spin lock + * areas of drm_vblank_put. + */ + void (*unprepare_vblank) (struct drm_device *dev, unsigned int pipe); + + + /** * enable_vblank - enable vblank interrupt events * @dev: DRM device * @pipe: which irq to enable @@ -720,6 +744,11 @@ struct drm_pending_vblank_event { struct drm_event_vblank event; }; +struct drm_vblank_unprepare { + struct work_struct work; /* Post disable worker */ + atomic_t counter; /* Number of vblanks handled */ +}; + struct drm_vblank_crtc { struct drm_device *dev; /* pointer to the drm_device */ wait_queue_head_t queue; /**< VBLANK wait queue */ @@ -740,6 +769,7 @@ struct drm_vblank_crtc { int linedur_ns; /* line duration in ns */ bool enabled; /* so we don't call enable more than once per disable */ + struct drm_vblank_unprepare unprepare; /* Unprepare work helper */ }; /**