From patchwork Fri Aug 19 09:40:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9289969 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 1134060574 for ; Fri, 19 Aug 2016 09:56:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 021372938F for ; Fri, 19 Aug 2016 09:56:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E99E429392; Fri, 19 Aug 2016 09:56:24 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7339E2938F for ; Fri, 19 Aug 2016 09:56:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754543AbcHSJ4V (ORCPT ); Fri, 19 Aug 2016 05:56:21 -0400 Received: from lucky1.263xmail.com ([211.157.147.130]:40802 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752244AbcHSJ4J (ORCPT ); Fri, 19 Aug 2016 05:56:09 -0400 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.233]) by lucky1.263xmail.com (Postfix) with SMTP id 3A3891EE483; Fri, 19 Aug 2016 17:44:58 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-ADDR-CHECKED: 0 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.263.net (Postfix) with ESMTP id C07EF39CC; Fri, 19 Aug 2016 17:44:52 +0800 (CST) X-RL-SENDER: shawn.lin@rock-chips.com X-FST-TO: jh80.chung@samsung.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: shawn.lin@rock-chips.com X-UNIQUE-TAG: <9a2502cf773087221372e04b39d430fe> X-ATTACHMENT-NUM: 0 X-SENDER: lintao@rock-chips.com X-DNS-TYPE: 0 Received: from unknown (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith SMTP id 7159FD3UD4; Fri, 19 Aug 2016 17:44:57 +0800 (CST) From: Shawn Lin To: Jaehoon Chung Cc: Ulf Hansson , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, Doug Anderson , Brian Norris , Heiko Stuebner , linux-rockchip@lists.infradead.org, Shawn Lin Subject: [PATCH 2/2] mmc: dw_mmc: avoid race condition of cpu and IDMAC Date: Fri, 19 Aug 2016 17:40:15 +0800 Message-Id: <1471599615-6249-2-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.8.0 In-Reply-To: <1471599615-6249-1-git-send-email-shawn.lin@rock-chips.com> References: <1471599615-6249-1-git-send-email-shawn.lin@rock-chips.com> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We could see an obvious race condition by test that the former write operation by IDMAC aiming to clear OWN bit reach right after the later configuration of the same desc, which makes the IDMAC be in SUSPEND state as the OWN bit was cleared by the asynchronous write operation of IDMAC. The bug can be very easy reproduced on RK3288 or similar when we reduce the running rate of system buses and keep the CPU running faster. So as two separate masters, IDMAC and cpu write the same descriptor stored on the same address, and this should be protected by adding check of OWN bit before preparing new descriptors. Signed-off-by: Shawn Lin --- drivers/mmc/host/dw_mmc.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0a5a49f..e640f83 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -473,6 +473,7 @@ static inline void dw_mci_prepare_desc64(struct dw_mci *host, { unsigned int desc_len; struct idmac_desc_64addr *desc_first, *desc_last, *desc; + unsigned long timeout = jiffies + msecs_to_jiffies(100); int i; desc_first = desc_last = desc = host->sg_cpu; @@ -489,6 +490,20 @@ static inline void dw_mci_prepare_desc64(struct dw_mci *host, length -= desc_len; /* + * Wait for the former clear OWN bit operation + * of IDMAC to make sure that this descriptor + * isn't still owned by IDMAC as IDMAC's write + * ops and CPU's read ops are asynchronous. + */ + while (readl(&desc->des0) & IDMAC_DES0_OWN) { + if (time_after(jiffies, timeout)) { + dev_err(host->dev, "DESC is still owned by IDMAC.\n"); + break; + } + udelay(10); + } + + /* * Set the OWN bit and disable interrupts * for this descriptor */ @@ -525,6 +540,7 @@ static inline void dw_mci_prepare_desc32(struct dw_mci *host, { unsigned int desc_len; struct idmac_desc *desc_first, *desc_last, *desc; + unsigned long timeout = jiffies + msecs_to_jiffies(100); int i; desc_first = desc_last = desc = host->sg_cpu; @@ -541,6 +557,20 @@ static inline void dw_mci_prepare_desc32(struct dw_mci *host, length -= desc_len; /* + * Wait for the former clear OWN bit operation + * of IDMAC to make sure that this descriptor + * isn't still owned by IDMAC as IDMAC's write + * ops and CPU's read ops are asynchronous. + */ + while (readl(&desc->des0) & IDMAC_DES0_OWN) { + if (time_after(jiffies, timeout)) { + dev_err(host->dev, "DESC is still owned by IDMAC.\n"); + break; + } + udelay(10); + } + + /* * Set the OWN bit and disable interrupts * for this descriptor */