From patchwork Wed Oct 3 22:31:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jae Hyun Yoo X-Patchwork-Id: 10625371 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A0E315A6 for ; Wed, 3 Oct 2018 22:34:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 187C42912C for ; Wed, 3 Oct 2018 22:34:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0B5C02912E; Wed, 3 Oct 2018 22:34:40 +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=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 79A3F2912C for ; Wed, 3 Oct 2018 22:34:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=+QUdrKPr51ZCIigmgGmny7s1Gyu6Eff6KIX9UTMNG/E=; b=Tfo1Gi2PnNKM1o o4u0JtHwH/G+gfD6JR1S45XorFN214F2zTb/R8681/9j/P5UonaQb0Zi7pSL4BapZb+ljIKdb8Acy OkrT/qBEEr0Z2VXimjesZUuk6VKvKz8ulHu9+WwEvFnPM+YMvXyJmivbBY+QMdO55xJ29RO5ggnxd 0OCC0ERPuxFzSHizJTgpgJQPDZj69ztgZK21uXIKASyhVOKAnf+h6bpMOVxsuaHtnxEsOvbPJb1GP tjWT66NW9ybMQ6Zo/UJiPdKckEQtbxNDGc9V6iNW07lk51847qaWkQpvKq73XcidgQv2UVw0fqE7s f74jzwk80AOaZgUv1GSw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1g7pj1-00016d-3S; Wed, 03 Oct 2018 22:34:35 +0000 Received: from mga17.intel.com ([192.55.52.151]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1g7pfv-00084V-EC for linux-arm-kernel@lists.infradead.org; Wed, 03 Oct 2018 22:31:28 +0000 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Oct 2018 15:31:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,337,1534834800"; d="scan'208";a="97208524" Received: from maru.jf.intel.com ([10.54.51.77]) by orsmga002.jf.intel.com with ESMTP; 03 Oct 2018 15:31:13 -0700 From: Jae Hyun Yoo To: Brendan Higgins , Wolfram Sang , Benjamin Herrenschmidt , Joel Stanley , Rob Herring , Mark Rutland , Andrew Jeffery , linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org Subject: [PATCH i2c-next v5 5/5] i2c: aspeed: Add bus idle waiting logic for multi-master use cases Date: Wed, 3 Oct 2018 15:31:07 -0700 Message-Id: <20181003223107.16133-6-jae.hyun.yoo@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181003223107.16133-1-jae.hyun.yoo@linux.intel.com> References: <20181003223107.16133-1-jae.hyun.yoo@linux.intel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181003_153123_515552_6EFC4CBD X-CRM114-Status: GOOD ( 19.20 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vernon Mauery , Jae Hyun Yoo , Jarkko Nikula , James Feist Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP In multi-master environment, this driver's master cannot know exactly when peer master sends data to this driver's slave so a case can be happened that this master tries to send data through the master_xfer function but slave data from peer master is still being processed by this driver. To prevent any state corruption in the case, this patch adds checking code if any slave operation is ongoing and it waits up to the bus timeout duration before starting a master_xfer operation. Signed-off-by: Jae Hyun Yoo --- drivers/i2c/busses/i2c-aspeed.c | 53 +++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 833b6b6a4c7e..8d60d7e5b323 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -115,6 +116,9 @@ /* 0x18 : I2CD Slave Device Address Register */ #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) +/* Busy checking */ +#define ASPEED_I2C_BUS_BUSY_CHECK_INTERVAL_US (10 * 1000) + enum aspeed_i2c_master_state { ASPEED_I2C_MASTER_INACTIVE, ASPEED_I2C_MASTER_START, @@ -156,6 +160,8 @@ struct aspeed_i2c_bus { int cmd_err; /* Protected only by i2c_lock_bus */ int master_xfer_result; + /* Multi-master */ + bool multi_master; #if IS_ENABLED(CONFIG_I2C_SLAVE) struct i2c_client *slave; enum aspeed_i2c_slave_state slave_state; @@ -596,27 +602,42 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) return irq_remaining ? IRQ_NONE : IRQ_HANDLED; } +static int aspeed_i2c_check_bus_busy(struct aspeed_i2c_bus *bus) +{ + ktime_t timeout; + + if (bus->multi_master) { + might_sleep(); + timeout = ktime_add_ms(ktime_get(), + jiffies_to_msecs(bus->adap.timeout)); + } + + for (;;) { + if (!(readl(bus->base + ASPEED_I2C_CMD_REG) & + ASPEED_I2CD_BUS_BUSY_STS) && + bus->slave_state == ASPEED_I2C_SLAVE_STOP) + return 0; + if (!bus->multi_master) + break; + if (ktime_compare(ktime_get(), timeout) > 0) + break; + usleep_range((ASPEED_I2C_BUS_BUSY_CHECK_INTERVAL_US >> 2) + 1, + ASPEED_I2C_BUS_BUSY_CHECK_INTERVAL_US); + } + + return aspeed_i2c_recover_bus(bus); +} + static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap); unsigned long time_left, flags; - int ret = 0; - spin_lock_irqsave(&bus->lock, flags); - bus->cmd_err = 0; - - /* If bus is busy, attempt recovery. We assume a single master - * environment. - */ - if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) { - spin_unlock_irqrestore(&bus->lock, flags); - ret = aspeed_i2c_recover_bus(bus); - if (ret) - return ret; - spin_lock_irqsave(&bus->lock, flags); - } + if (aspeed_i2c_check_bus_busy(bus)) + return -EAGAIN; + spin_lock_irqsave(&bus->lock, flags); bus->cmd_err = 0; bus->msgs = msgs; bus->msgs_index = 0; @@ -827,7 +848,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, if (ret < 0) return ret; - if (!of_property_read_bool(pdev->dev.of_node, "multi-master")) + if (of_property_read_bool(pdev->dev.of_node, "multi-master")) + bus->multi_master = true; + else fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS; /* Enable Master Mode */