Received: by 10.223.185.116 with SMTP id b49csp697302wrg; Fri, 16 Feb 2018 05:52:04 -0800 (PST) X-Google-Smtp-Source: AH8x225MmBSl6aCakJ3/hUN1hwJBUQNax55qFYhk7mCeYRZxFv6ckME4Xzy31j+2tuMA7A2l9N5B X-Received: by 10.98.194.18 with SMTP id l18mr6260728pfg.118.1518789124068; Fri, 16 Feb 2018 05:52:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518789124; cv=none; d=google.com; s=arc-20160816; b=SrK51iqF8cvCWajaxiB5JYLQySp6yb4fPlA9Uoj08b+cmmWWnp55IamOMdwzaURp5d nnq/g/2VEO+UPGC+PmiRYqknRzZPuwmdc2BZZjoC4i61KTW0NB/pooU4ziJ0UYPaeno6 uWfVgRpU5c30lstxMSwNC9A+28uZVg/TXjnFTCvWwPy9o80xgmhEpfV9vTXhbOeu6um2 MhbdeKP5T0KWOR+r6dj8rjKYCaNtyxVtjTqU38lfsicRScgWmJEEytdu1TSEcnvBTeIi iWX1jBJwJtbJRV5uFJPfsDBLUMWV9T9GJvPKB4PPcmlV3dPOXvTgVdkb+jlRnLWToqKl SrNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=aZzyfSVy2MTJWMiOwA9qPlojGH+G61KIybC9lRN4PwE=; b=GwLWSaUf8ZTrKfatKLoYEn+TLvGMqLdhouA3m8Dh4EE6b+ZH4EtXxcPIvz72N+wJ6U lr/T0lXcABMU5E8gyCtQmiHBfp2vQMzq//A7lxK1sRZstwsSU9jTbAaED47ZEHEECXY5 jpsUPtyDpPr6WDa1GMWHYo7dOLqWNrczbraAUhnw0GfVR3wMFCAEFIkwe3GyzERZtO8q 3QWv3FOt8LeHPdPJ0vpucR80hWGB7WF7YNwYF2Gf6GpGdrqGa/hiQ5nmrWtm7scVx0k6 LaCgUAYcd8/lFCQfIlCI2gWqs98znBu/iVYqidwtfDM6jJ8srIhEK+AQIIMCw8/UJ+Dz vrXg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z2si2823399pgb.755.2018.02.16.05.51.49; Fri, 16 Feb 2018 05:52:04 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1166923AbeBOSvW (ORCPT + 99 others); Thu, 15 Feb 2018 13:51:22 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:48982 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1162064AbeBOPV2 (ORCPT ); Thu, 15 Feb 2018 10:21:28 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 260288E2; Thu, 15 Feb 2018 15:21:27 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Laurent Pinchart , Kieran Bingham , thongsyho , Nhan Nguyen Subject: [PATCH 4.4 025/108] drm: rcar-du: Fix race condition when disabling planes at CRTC stop Date: Thu, 15 Feb 2018 16:16:22 +0100 Message-Id: <20180215151226.076346687@linuxfoundation.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180215151222.267507937@linuxfoundation.org> References: <20180215151222.267507937@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.4-stable review patch. If anyone has any objections, please let me know. ------------------ From: Laurent Pinchart commit 641307df71fe77d7b38a477067495ede05d47295 upstream. When stopping the CRTC the driver must disable all planes and wait for the change to take effect at the next vblank. Merely calling drm_crtc_wait_one_vblank() is not enough, as the function doesn't include any mechanism to handle the race with vblank interrupts. Replace the drm_crtc_wait_one_vblank() call with a manual mechanism that handles the vblank interrupt race. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: thongsyho Signed-off-by: Nhan Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 54 +++++++++++++++++++++++++++++---- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 ++++ 2 files changed, 56 insertions(+), 6 deletions(-) --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -371,6 +371,31 @@ static void rcar_du_crtc_start(struct rc rcrtc->started = true; } +static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->group->dev; + struct drm_crtc *crtc = &rcrtc->crtc; + u32 status; + /* Make sure vblank interrupts are enabled. */ + drm_crtc_vblank_get(crtc); + /* + * Disable planes and calculate how many vertical blanking interrupts we + * have to wait for. If a vertical blanking interrupt has been triggered + * but not processed yet, we don't know whether it occurred before or + * after the planes got disabled. We thus have to wait for two vblank + * interrupts in that case. + */ + spin_lock_irq(&rcrtc->vblank_lock); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); + status = rcar_du_crtc_read(rcrtc, DSSR); + rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1; + spin_unlock_irq(&rcrtc->vblank_lock); + if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0, + msecs_to_jiffies(100))) + dev_warn(rcdu->dev, "vertical blanking timeout\n"); + drm_crtc_vblank_put(crtc); +} + static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; @@ -379,17 +404,16 @@ static void rcar_du_crtc_stop(struct rca return; /* Disable all planes and wait for the change to take effect. This is - * required as the DSnPR registers are updated on vblank, and no vblank - * will occur once the CRTC is stopped. Disabling planes when starting - * the CRTC thus wouldn't be enough as it would start scanning out - * immediately from old frame buffers until the next vblank. + * required as the plane enable registers are updated on vblank, and no + * vblank will occur once the CRTC is stopped. Disabling planes when + * starting the CRTC thus wouldn't be enough as it would start scanning + * out immediately from old frame buffers until the next vblank. * * This increases the CRTC stop delay, especially when multiple CRTCs * are stopped in one operation as we now wait for one vblank per CRTC. * Whether this can be improved needs to be researched. */ - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); - drm_crtc_wait_one_vblank(crtc); + rcar_du_crtc_disable_planes(rcrtc); /* Disable vertical blanking interrupt reporting. We first need to wait * for page flip completion before stopping the CRTC as userspace @@ -528,10 +552,26 @@ static irqreturn_t rcar_du_crtc_irq(int irqreturn_t ret = IRQ_NONE; u32 status; + spin_lock(&rcrtc->vblank_lock); + status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); if (status & DSSR_VBK) { + /* + * Wake up the vblank wait if the counter reaches 0. This must + * be protected by the vblank_lock to avoid races in + * rcar_du_crtc_disable_planes(). + */ + if (rcrtc->vblank_count) { + if (--rcrtc->vblank_count == 0) + wake_up(&rcrtc->vblank_wait); + } + } + + spin_unlock(&rcrtc->vblank_lock); + + if (status & DSSR_VBK) { drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; @@ -585,6 +625,8 @@ int rcar_du_crtc_create(struct rcar_du_g } init_waitqueue_head(&rcrtc->flip_wait); + init_waitqueue_head(&rcrtc->vblank_wait); + spin_lock_init(&rcrtc->vblank_lock); rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index]; --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,6 +15,7 @@ #define __RCAR_DU_CRTC_H__ #include +#include #include #include @@ -32,6 +33,9 @@ struct rcar_du_group; * @started: whether the CRTC has been started and is running * @event: event to post when the pending page flip completes * @flip_wait: wait queue used to signal page flip completion + * @vblank_lock: protects vblank_wait and vblank_count + * @vblank_wait: wait queue used to signal vertical blanking + * @vblank_count: number of vertical blanking interrupts to wait for * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC * @enabled: whether the CRTC is enabled, used to control system resume * @group: CRTC group this CRTC belongs to @@ -48,6 +52,10 @@ struct rcar_du_crtc { struct drm_pending_vblank_event *event; wait_queue_head_t flip_wait; + spinlock_t vblank_lock; + wait_queue_head_t vblank_wait; + unsigned int vblank_count; + unsigned int outputs; bool enabled;