Received: by 2002:ac0:98c7:0:0:0:0:0 with SMTP id g7-v6csp3900036imd; Mon, 29 Oct 2018 14:15:31 -0700 (PDT) X-Google-Smtp-Source: AJdET5clw5ob7OvDqpNm4mfVlyTFzzYR+sl0r/HfEU7uG0hJeEGM3F9/kK5An2jUaRvEmSPEKJKY X-Received: by 2002:a63:6b08:: with SMTP id g8mr15222016pgc.119.1540847731827; Mon, 29 Oct 2018 14:15:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540847731; cv=none; d=google.com; s=arc-20160816; b=tT4+YwBjsLgeJiQ9ydQMKwUWq88WBxKtCX4F6wslLQ1EPMBz01xHcMZRg5S0cKw92M 7wf6B4kdryt5qPVnaH8i8qHpCpUl/qdfIzz+ihpl5RfRrVNu5imUxMCHhsJh2tUJc6Vo sgT326rTUP/2EyeH1VYlOOFuxVC+2e/6+QwXOrRs30dXShZBP29llm6F9iPRBhqT6yxE CMCDc5h9C6oJaY6jB6SBQtoIn7ClBWmZI2L9lh3uWUDAg25l/JqdvrHSfz6Q2Yv24ldQ zx+zcKfruQ2PUAR6p9PbMvKYpUnMoVkCQ4JgOt/NsYzWjUl/TrYOFlHyWPncDuJOCw82 uYeQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=/dUaSCPvOOg/e9JO4xjL5t+6oEBaze4SJ9gC5HzgktM=; b=x8KNI+URVAJ9bgYxnyXCsONegy5xXp3LU0KdCDAg+q94zJxum6gL2Lj+Sb5Mm/KqW/ noMS5dmLQ6mFuHnjg+jpAKZIYBODBh9DUK5pUUIBuhENpIs3I9Uj1iLtdPK8AdM6vZSX p8rZX6sGc9gjU3gX2xWpnXizD3LHMPUcrWvHRVzRIysjhPSq+bpVca4GrKxUpY8VIxqX RZoM7gtMyYHs+YKPgglWDi8mdI5v/ZDrMhfuyng3/UA9uQj//0eNi02qrdh6oq+BxxFI D4ctJhqGKKBg3OKgKBlywvyCebl7F07FwEtXcpzBVYN4EsQwP6sXXjqAQUoQEVM52mOI j8RQ== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f7-v6si19976612pgh.159.2018.10.29.14.15.16; Mon, 29 Oct 2018 14:15:31 -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; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727804AbeJ3GFQ (ORCPT + 99 others); Tue, 30 Oct 2018 02:05:16 -0400 Received: from mga06.intel.com ([134.134.136.31]:36152 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726616AbeJ3GFN (ORCPT ); Tue, 30 Oct 2018 02:05:13 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 29 Oct 2018 14:14:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,441,1534834800"; d="scan'208";a="275456018" Received: from maru.jf.intel.com ([10.54.51.77]) by fmsmga005.fm.intel.com with ESMTP; 29 Oct 2018 14:14:47 -0700 From: Jae Hyun Yoo To: Wolfram Sang , Brendan Higgins , Rob Herring , Joel Stanley , Benjamin Herrenschmidt , 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 Cc: Jarkko Nikula , James Feist , Vernon Mauery , Jae Hyun Yoo Subject: [PATCH i2c-next v8 5/5] i2c: aspeed: Add bus idle waiting logic for multi-master use cases Date: Mon, 29 Oct 2018 14:14:14 -0700 Message-Id: <20181029211414.20771-6-jae.hyun.yoo@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181029211414.20771-1-jae.hyun.yoo@linux.intel.com> References: <20181029211414.20771-1-jae.hyun.yoo@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In multi-master environment, this driver's master cannot know exactly when a 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 Reviewed-by: Brendan Higgins --- drivers/i2c/busses/i2c-aspeed.c | 52 +++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 833b6b6a4c7e..4e92a405210b 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,41 @@ 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) +{ + unsigned long check_started; + + if (bus->multi_master) { + might_sleep(); + check_started = jiffies; + } + + 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 (time_after(jiffies, check_started + bus->adap.timeout)) + 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 +847,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 */ -- 2.19.1