From patchwork Thu Mar 5 02:26:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Haixia Shi X-Patchwork-Id: 5942941 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.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 801699F380 for ; Thu, 5 Mar 2015 02:31:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7CB76202B8 for ; Thu, 5 Mar 2015 02:31:23 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2810C202AE for ; Thu, 5 Mar 2015 02:31:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 74A9A6E729; Wed, 4 Mar 2015 18:31:19 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-ig0-f182.google.com (mail-ig0-f182.google.com [209.85.213.182]) by gabe.freedesktop.org (Postfix) with ESMTP id 20DE56E729 for ; Wed, 4 Mar 2015 18:31:18 -0800 (PST) Received: by igdh15 with SMTP id h15so42290245igd.3 for ; Wed, 04 Mar 2015 18:31:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version:content-type :content-transfer-encoding; bh=WsjGe62Zv9VJv1LZNSd/bQ+EVPTZgS7y+sMqnFEjm7c=; b=NkGJ4tY2aPeHcmYnjyc9Ixen2xra2LLaQaBmLzvpiyIS06JldZYDVqDpD8DwcEsx0Q 8yIABU2cvLO4YJtStsnAvcsBp1W+LUWPecu9jCbXNhngHbb5ORDfF2UiBMMpX8CgD8Hq taLLVlk/dCAANSiv+svvzRVZjubet+j373Tp4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-type:content-transfer-encoding; bh=WsjGe62Zv9VJv1LZNSd/bQ+EVPTZgS7y+sMqnFEjm7c=; b=OiKEbfsnvwG35RALSaWx+J79AWBHX2W+2b3m+r/kNI415w45pno+nx8y+fiRen5nGH cx19707jKNVVUFU7nba0YKxNAY3bASjLGGUZt/eq8eEslkSJ2hidlGxAzbaJdIzE7Dad HQkSF0rGmR7EYYJ6kofhhocvhxN8JT0mYPRI3Kr6+IBOQtYhqBJ9afmMXkckfiqdlJeL dKoztEBFmQinzG25QulSO0IOussfZ29zI28yHTJpn500GHU+TarNgVXuGeHKbyeStTVn 2PEmFnf/iwLHA6l4MX/H/ZBKur3AEULCcw0njVVSozK5GJcZHr56QzmmfOe50tS9bpaU Luvw== X-Gm-Message-State: ALoCoQnreIQ8GGekhYbyR1cLeLPa44qFfA73GNXtJ8we7s7cHq9TT3A6wOFFgS2PiLYVHHE0GSQ6 X-Received: by 10.107.15.68 with SMTP id x65mr17311749ioi.39.1425522677498; Wed, 04 Mar 2015 18:31:17 -0800 (PST) Received: from localhost ([2620:0:1000:1600:1105:4692:5df2:5db6]) by mx.google.com with ESMTPSA id z29sm4068679ioi.36.2015.03.04.18.31.14 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Wed, 04 Mar 2015 18:31:15 -0800 (PST) From: Haixia Shi To: dri-devel@lists.freedesktop.org Subject: [PATCH 1/2] drm/udl: make page flips asynchronous. Date: Wed, 4 Mar 2015 18:26:23 -0800 Message-Id: <1425522384-40559-1-git-send-email-hshi@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c MIME-Version: 1.0 Cc: Haixia Shi 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: , 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_SIGNED, 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 This also limits the maximum frequency of page flips by the vrefresh rate. Signed-off-by: Haixia Shi Reviewed-by: Stéphane Marchesin Tested-by: Haixia Shi --- drivers/gpu/drm/udl/udl_drv.h | 3 + drivers/gpu/drm/udl/udl_modeset.c | 129 ++++++++++++++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 80adbac..b1e9fae 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -47,6 +47,7 @@ struct urb_list { }; struct udl_fbdev; +struct udl_flip_queue; struct udl_device { struct device *dev; @@ -65,6 +66,8 @@ struct udl_device { atomic_t bytes_identical; /* saved effort with backbuffer comparison */ atomic_t bytes_sent; /* to usb, after compression including overhead */ atomic_t cpu_kcycles_used; /* transpired during pixel processing */ + + struct udl_flip_queue *flip_queue; }; struct udl_gem_object { diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 677190a6..f3804b4 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -303,6 +303,16 @@ udl_pipe_set_base(struct drm_crtc *crtc, int x, int y, } #endif +struct udl_flip_queue { + struct mutex lock; + struct workqueue_struct *wq; + struct delayed_work work; + struct drm_crtc *crtc; + struct drm_pending_vblank_event *event; + u64 flip_time; /* in jiffies */ + u64 vblank_interval; /* in jiffies */ +}; + static int udl_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -313,6 +323,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb); struct udl_device *udl = dev->dev_private; + struct udl_flip_queue *flip_queue = udl->flip_queue; char *buf; char *wrptr; int color_depth = 0; @@ -347,6 +358,13 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc, ufb->active_16 = true; udl->mode_buf_len = wrptr - buf; + /* update flip queue vblank interval */ + if (flip_queue) { + mutex_lock(&flip_queue->lock); + flip_queue->vblank_interval = HZ / mode->vrefresh; + mutex_unlock(&flip_queue->lock); + } + /* damage all of it */ udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height); return 0; @@ -364,29 +382,82 @@ static void udl_crtc_destroy(struct drm_crtc *crtc) kfree(crtc); } +static void udl_sched_page_flip(struct work_struct *work) +{ + struct udl_flip_queue *flip_queue = + container_of(container_of(work, struct delayed_work, work), + struct udl_flip_queue, work); + struct drm_crtc *crtc; + struct drm_device *dev; + struct drm_pending_vblank_event *event; + struct drm_framebuffer *fb; + + mutex_lock(&flip_queue->lock); + crtc = flip_queue->crtc; + dev = crtc->dev; + event = flip_queue->event; + fb = crtc->primary->fb; + flip_queue->event = NULL; + mutex_unlock(&flip_queue->lock); + + if (fb) + udl_handle_damage(to_udl_fb(fb), 0, 0, fb->width, fb->height); + if (event) { + unsigned long flags; + spin_lock_irqsave(&dev->event_lock, flags); + drm_send_vblank_event(dev, 0, event); + spin_unlock_irqrestore(&dev->event_lock, flags); + } +} + static int udl_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) { - struct udl_framebuffer *ufb = to_udl_fb(fb); struct drm_device *dev = crtc->dev; - unsigned long flags; + struct udl_device *udl = dev->dev_private; + struct udl_flip_queue *flip_queue = udl->flip_queue; - struct drm_framebuffer *old_fb = crtc->primary->fb; - if (old_fb) { - struct udl_framebuffer *uold_fb = to_udl_fb(old_fb); - uold_fb->active_16 = false; + if (!flip_queue || !flip_queue->wq) { + DRM_ERROR("Uninitialized page flip queue\n"); + return -ENOMEM; } - ufb->active_16 = true; - udl_handle_damage(ufb, 0, 0, fb->width, fb->height); + mutex_lock(&flip_queue->lock); + + flip_queue->crtc = crtc; + if (fb) { + struct drm_framebuffer *old_fb; + struct udl_framebuffer *ufb; + ufb = to_udl_fb(fb); + old_fb = crtc->primary->fb; + if (old_fb) { + struct udl_framebuffer *uold_fb = to_udl_fb(old_fb); + uold_fb->active_16 = false; + } + ufb->active_16 = true; + crtc->primary->fb = fb; + } + if (event) { + if (flip_queue->event) { + unsigned long flags; + spin_lock_irqsave(&dev->event_lock, flags); + drm_send_vblank_event(dev, 0, flip_queue->event); + spin_unlock_irqrestore(&dev->event_lock, flags); + } + flip_queue->event = event; + } + if (!delayed_work_pending(&flip_queue->work)) { + u64 now = jiffies; + u64 next_flip = + flip_queue->flip_time + flip_queue->vblank_interval; + flip_queue->flip_time = (next_flip < now) ? now : next_flip; + queue_delayed_work(flip_queue->wq, &flip_queue->work, + flip_queue->flip_time - now); + } - spin_lock_irqsave(&dev->event_lock, flags); - if (event) - drm_send_vblank_event(dev, 0, event); - spin_unlock_irqrestore(&dev->event_lock, flags); - crtc->primary->fb = fb; + mutex_unlock(&flip_queue->lock); return 0; } @@ -429,6 +500,35 @@ static int udl_crtc_init(struct drm_device *dev) return 0; } +static void udl_flip_workqueue_init(struct drm_device *dev) +{ + struct udl_device *udl = dev->dev_private; + struct udl_flip_queue *flip_queue = + kzalloc(sizeof(struct udl_flip_queue), GFP_KERNEL); + BUG_ON(!flip_queue); + mutex_init(&flip_queue->lock); + flip_queue->wq = create_singlethread_workqueue("flip"); + BUG_ON(!flip_queue->wq); + INIT_DELAYED_WORK(&flip_queue->work, udl_sched_page_flip); + flip_queue->flip_time = jiffies; + flip_queue->vblank_interval = HZ / 60; + udl->flip_queue = flip_queue; +} + +static void udl_flip_workqueue_cleanup(struct drm_device *dev) +{ + struct udl_device *udl = dev->dev_private; + struct udl_flip_queue *flip_queue = udl->flip_queue; + if (!flip_queue) + return; + if (flip_queue->wq) { + flush_workqueue(flip_queue->wq); + destroy_workqueue(flip_queue->wq); + } + mutex_destroy(&flip_queue->lock); + kfree(flip_queue); +} + static const struct drm_mode_config_funcs udl_mode_funcs = { .fb_create = udl_fb_user_fb_create, .output_poll_changed = NULL, @@ -458,10 +558,13 @@ int udl_modeset_init(struct drm_device *dev) udl_connector_init(dev, encoder); + udl_flip_workqueue_init(dev); + return 0; } void udl_modeset_cleanup(struct drm_device *dev) { + udl_flip_workqueue_cleanup(dev); drm_mode_config_cleanup(dev); }