From patchwork Tue Oct 16 03:01:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 148904 Delivered-To: patch@linaro.org Received: by 2002:a2e:8595:0:0:0:0:0 with SMTP id b21-v6csp4543690lji; Mon, 15 Oct 2018 20:03:03 -0700 (PDT) X-Google-Smtp-Source: ACcGV63oG9afibHlIX7LGe986Yx+OtB6bhvrF7RtWLl0YVpOebKAaQ9BRSmdYVyHCOoOYZ2qoN/h X-Received: by 2002:a17:902:760b:: with SMTP id k11-v6mr19794798pll.103.1539658983768; Mon, 15 Oct 2018 20:03:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1539658983; cv=none; d=google.com; s=arc-20160816; b=cmRqweziKiIc61+7bm+KzgiJKYNLNp7a2naWyhI2UmtQolPhXtaL4B0WADSOmIhsBW EQ0ymIfZGfLWBEwTPo+WFDJrsZdTJYzAXLJKn3g4uu83ffeohBF8sgspDPuRLhR/xTkS Tnzb3OSrIUM210dk8Sjf7sG8jtFhZ2t1U3LlNVK2vF2CuHRkJHV31YYczUwpYBKFEc+c I75hK48v8+/voFCbwD8H0aL21OiGmzSxSrdVgm5r6Zt6VVI6dN7QV9rfmck9JY2bw4GZ yfcjWNor/W2mY2Qss9JPBmFnIPUX/EV1SOS21lRRKgPGckJy7+1vsJSTaHyOgmn7rXcq CaNA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter; bh=0jExx5vDSGpy/qM7ZAif6aEaMMZKi5fc6yONUDddKPc=; b=G+ON0t2+fzXSuJlCIYNCp6i47p8GugmsYsb+o6t2RPoR/2qYSUio6mjm9E/egnGdO0 5TPLaXmAWO1cfrbQOVZFS+s1h3BDwkqfEb0Y0f2DQPCEAt6+iLJr2zhoMMGUO1y7uRV3 u9rNArl4PovjGfEr1cveuj3Gw8psqBK6UErnNxRfBAtyfNA7XNIe0OKph/EL0YYH8zF8 h3nju+kAu5we4kD8wwZVg3RMUl0JWwvUNEk4ewJEZ4FfLA3FBpGy1xo4x7IP0KBwMHim CKZqu5G+YS2EFR7CYmUOrN1eVvjf1mXwGvm0vyMYlPUWjN+0Vpgb8iO0fNffmvSJffru mLNQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com header.s=dec2015msa header.b=wFAcg1yh; 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 32-v6si12711702pls.207.2018.10.15.20.03.03; Mon, 15 Oct 2018 20:03:03 -0700 (PDT) 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; dkim=pass header.i=@nifty.com header.s=dec2015msa header.b=wFAcg1yh; 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 S1727481AbeJPKvJ (ORCPT + 32 others); Tue, 16 Oct 2018 06:51:09 -0400 Received: from conuserg-12.nifty.com ([210.131.2.79]:45922 "EHLO conuserg-12.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727360AbeJPKun (ORCPT ); Tue, 16 Oct 2018 06:50:43 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-12.nifty.com with ESMTP id w9G31q7F017707; Tue, 16 Oct 2018 12:01:53 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-12.nifty.com w9G31q7F017707 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1539658914; bh=0jExx5vDSGpy/qM7ZAif6aEaMMZKi5fc6yONUDddKPc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wFAcg1yhovR2BD7Pa1BaDM4Iwz5LBV8e8+Scpc+tokw5T1tsVE+y0f4GF3PfuaFYW ALMTN4QAsCTmGD548ePzCImxsg7YQ89yWEEHheqmeByeO9wrq4DPAXBuKFYFCnlyWK 7ezAJf4tV1ttEVMsvIi+vYxuqCDHzBRfK8MrpuLGAtc15d1MNdC1sXPAoqMCw6WZu8 VIyrMhOCHqo0yvFRZqoN1koxjhwQbSOL/5EbbMx41qaQzUxoqGxqT5M396Ly4FGiUU 3mpUrT63Xx7lwxnKKvZJ5o55eFL3gXtPQcefyuhsV7EwbuMQk6KUPDlRJwN6Lovt8E DA/jlMzPRkUyA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: Wolfram Sang , linux-i2c@vger.kernel.org Cc: Masahiro Yamada , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/3] i2c: uniphier-f: fix occasional timeout error Date: Tue, 16 Oct 2018 12:01:48 +0900 Message-Id: <1539658909-26691-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1539658909-26691-1-git-send-email-yamada.masahiro@socionext.com> References: <1539658909-26691-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently, a timeout error could happen at a repeated START condition. For a (non-repeated) START condition, the controller starts sending data when the UNIPHIER_FI2C_CR_STA bit is set. However, for a repeated START condition, the hardware starts running when the slave address is written to the TX FIFO - the write to the UNIPHIER_FI2C_CR register is actually unneeded. Because the hardware is already running before the IRQ is enabled for a repeated START, the driver may miss the IRQ event. In most cases, this problem does not show up since modern CPUs are much faster than the I2C transfer. However, it is still possible that a context switch happens after the controller starts, but before the IRQ register is set up. To fix this, - Do not write UNIPHIER_FI2C_CR for repeated START conditions. - Enable IRQ *before* writing the slave address to the TX FIFO. - Disable IRQ for the current CPU while queuing up the TX FIFO; If the CPU is interrupted by some task, the interrupt handler might be invoked due to the empty TX FIFO before completing the setup. Fixes: 6a62974b667f ("i2c: uniphier_f: add UniPhier FIFO-builtin I2C driver") Signed-off-by: Masahiro Yamada --- drivers/i2c/busses/i2c-uniphier-f.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index 200dfd1..0677153 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -260,6 +260,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr) { priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE; + uniphier_fi2c_set_irqs(priv); + /* do not use TX byte counter */ writel(0, priv->membase + UNIPHIER_FI2C_TBC); /* set slave address */ @@ -292,6 +294,8 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr) priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF; } + uniphier_fi2c_set_irqs(priv); + /* set slave address with RD bit */ writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1, priv->membase + UNIPHIER_FI2C_DTTX); @@ -315,14 +319,16 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) } static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, - struct i2c_msg *msg, bool stop) + struct i2c_msg *msg, bool repeat, + bool stop) { struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); bool is_read = msg->flags & I2C_M_RD; unsigned long time_left, flags; - dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", - is_read ? "receive" : "transmit", msg->addr, msg->len, stop); + dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n", + is_read ? "receive" : "transmit", msg->addr, msg->len, + repeat, stop); priv->len = msg->len; priv->buf = msg->buf; @@ -338,16 +344,24 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST, priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */ + spin_lock_irqsave(&priv->lock, flags); + if (is_read) uniphier_fi2c_rx_init(priv, msg->addr); else uniphier_fi2c_tx_init(priv, msg->addr); - uniphier_fi2c_set_irqs(priv); - dev_dbg(&adap->dev, "start condition\n"); - writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA, - priv->membase + UNIPHIER_FI2C_CR); + /* + * For a repeated START condition, writing a slave address to the FIFO + * kicks the controller. So, the UNIPHIER_FI2C_CR register should be + * written only for a non-repeated START condition. + */ + if (!repeat) + writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA, + priv->membase + UNIPHIER_FI2C_CR); + + spin_unlock_irqrestore(&priv->lock, flags); time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); @@ -408,6 +422,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *msg, *emsg = msgs + num; + bool repeat = false; int ret; ret = uniphier_fi2c_check_bus_busy(adap); @@ -418,9 +433,11 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, /* Emit STOP if it is the last message or I2C_M_STOP is set. */ bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); - ret = uniphier_fi2c_master_xfer_one(adap, msg, stop); + ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop); if (ret) return ret; + + repeat = !stop; } return num;