Received: by 10.223.176.5 with SMTP id f5csp705125wra; Fri, 9 Feb 2018 06:00:31 -0800 (PST) X-Google-Smtp-Source: AH8x224uLYI1QWe1HP3x7hkcUT46aUZjeBjYfGmI4+SzrVRGx2Q3KvfDvPeLySXU6TU8hgN9Jsjx X-Received: by 10.98.76.141 with SMTP id e13mr2955900pfj.160.1518184831673; Fri, 09 Feb 2018 06:00:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518184831; cv=none; d=google.com; s=arc-20160816; b=CkD4BklYxgtzLjhyM6kDsXc4LLb7a0aKnQTIQuiCYtaC3FSdBIFDfg1Nntb2DY9D8K f7yLqnRYxyDv/ob5HJxgX+QkOl5pDuPu3F7e32bRKc7Y9jROQqFDJNns81628I66XraM tBb+I7LslOw8h72n0iwmHPDiLaNCjpBC5JSajldl4ip1ZiB8MB62dkc6F/9bYbpZ17gR zIEgMZ21UEnjQ6J5utMbh3uhYlGz3T+T4mGYBlSSK2MRUrSqwbm8Gn7ZoVux7V58KxMS jMhWOwqOEsUTnr03SFqUl4PDnX8dcTfw9oqP45ZQFo0AYIpxPKg6hnHjab1iyy350WfW Zt/g== 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=mhk0glijs99xwIyq62OVwjoFI95UROO9Rr5hYsB/EYc=; b=R8izEN1pgxnETym6ffHOr2c9k93UDUPCAgyo4thDNYMLRIrG10kr/SukA2lKU4Q31f SSvF0luG2AbLigvsVu+NtMBtoQtQNLDBwq47wDn39o042RtzOvZTXtHKeS3FqVrGtPeg FRhsbESVfWjtdCe+y2dTi0Q8PB9ueKcAaidOb/sfMwUu0pb13rlQ6pD/wq79ndh8FPKI YLezVEwhdeqDHq6NtQeExSTP5204Zm6VP5X9WgYW6EecsI1fQlTqJwX0jmb45EVnM/H1 lyiPf73qIimaekv9Ma55EnGMXJTz49dr9bPaU4TMEuK847AwF3A6ZFaHjsRU652l6rP8 yQGw== 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 j71si1400982pgd.404.2018.02.09.06.00.16; Fri, 09 Feb 2018 06:00:31 -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 S1753483AbeBIN5m (ORCPT + 99 others); Fri, 9 Feb 2018 08:57:42 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:51590 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752862AbeBINou (ORCPT ); Fri, 9 Feb 2018 08:44:50 -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 9CC9AFF5; Fri, 9 Feb 2018 13:44:49 +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.9 91/92] drm: rcar-du: Fix race condition when disabling planes at CRTC stop Date: Fri, 9 Feb 2018 14:40:00 +0100 Message-Id: <20180209133937.566943626@linuxfoundation.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180209133931.211869118@linuxfoundation.org> References: <20180209133931.211869118@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.9-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 | 53 +++++++++++++++++++++++++++++---- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 ++++ 2 files changed, 55 insertions(+), 6 deletions(-) --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -392,6 +392,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; @@ -400,17 +425,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 @@ -548,10 +572,25 @@ 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_crtc_handle_vblank(&rcrtc->crtc); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; @@ -606,6 +645,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 @@ -33,6 +34,9 @@ struct rcar_du_vsp; * @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 * @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; struct rcar_du_group *group;