From patchwork Fri May 19 05:52:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dhinakaran Pandiyan X-Patchwork-Id: 9170457 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 873E46048F for ; Fri, 10 Jun 2016 21:21:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7678327D13 for ; Fri, 10 Jun 2016 21:21:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6B46C28356; Fri, 10 Jun 2016 21:21:28 +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, T_DATE_IN_FUTURE_Q_PLUS 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 D502927D13 for ; Fri, 10 Jun 2016 21:21:27 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BAE1C6E1E1; Fri, 10 Jun 2016 21:21:26 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTP id 5EDE46E1E1 for ; Fri, 10 Jun 2016 21:21:25 +0000 (UTC) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga102.jf.intel.com with ESMTP; 10 Jun 2016 14:21:18 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,452,1459839600"; d="scan'208";a="999552386" Received: from skylake.jf.intel.com ([10.54.75.142]) by fmsmga002.fm.intel.com with ESMTP; 10 Jun 2016 14:21:18 -0700 From: Dhinakaran Pandiyan To: intel-gfx@lists.freedesktop.org Date: Thu, 18 May 2017 22:52:21 -0700 Message-Id: <1495173141-11669-1-git-send-email-dhinakaran.pandiyan@intel.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1465436764-29950-2-git-send-email-dhinakaran.pandiyan@intel.com> References: <1465436764-29950-2-git-send-email-dhinakaran.pandiyan@intel.com> Subject: [Intel-gfx] REBASED: [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 --- Rebased. 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 5a773e4..bdf01cd 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -347,6 +347,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); @@ -355,6 +357,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 @@ -388,6 +404,8 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) setup_timer(&vblank->disable_timer, vblank_disable_fn, (unsigned long)vblank); seqlock_init(&vblank->seqlock); + INIT_WORK(&vblank->unprepare.work, + drm_vblank_unprepare_work_fn); } DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); @@ -1170,6 +1188,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) { @@ -1182,6 +1203,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); @@ -1234,6 +1258,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); @@ -1668,7 +1695,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 c5d2950..7495f56 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -443,6 +443,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 @@ -716,6 +740,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 */ @@ -736,6 +765,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 */ }; /**