Received: by 2002:ac0:a582:0:0:0:0:0 with SMTP id m2-v6csp499108imm; Mon, 1 Oct 2018 13:28:41 -0700 (PDT) X-Google-Smtp-Source: ACcGV632zdn23daLx8MK8MuzMSeKtcZw9xvUOn6U1WN7ltkED/nk6/N/2Xemb0FW3QBe6vYhUbLi X-Received: by 2002:a17:902:b70d:: with SMTP id d13-v6mr13221954pls.44.1538425721264; Mon, 01 Oct 2018 13:28:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1538425721; cv=none; d=google.com; s=arc-20160816; b=iqHMRURqR59L8fM6r/8oUe5phAq9zkn3UJ5bcRtWnf1ZV9YN+7FXZhwbdLeCT5XlsG lapmRI9EH9mu6rsjRmKhYtmx9jPFLPgjw8Pwg1jkcqHr73pT+RiKVLqk8ZOxk4FPgQ3V troil8qr1X2rtgJP5HMSa2odjvIyMQT/72TT4B6Us0H/IA/u9onpBcPO0inPjtXLyswA T0XM80HL63hjCdKKDTKt1mqfIoJaQ1VRYZYZRlJZb+qB6HH96A/yBU8jQwrRIHICYArt b/8X4aLM0vDPU+JkGyhi/fHioGQgbKoMyCxcnb57xeywUI90dJZT7hSCu32wdxxmt6AO 7I9w== 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=r5ok5PFHThSDMx8jx2bZ2ebACCMoYSVJLz1SbaRwLDQ=; b=O6WppUrvmP2XJPeUwiKpXOYrfnt7pZho1O6+QhWmMvhOWZiAWhbLdaNgsbQ6DHS3NJ n3dOkV9bErPxHTAVHnBdS12c6oGYjI7D04x9Pu5nv5s2iAchd+5pol5QRLqoElewx6Rp nYBsF0FAmea0GX1/q9+m4KbuepHdKOQ1NaXbLOKBRMKKnWvXvVpKz+VXitMBispl6xF/ oz//EsLAT7D/vvwEM4ubtUCjFbzHzU5iN+d4iMF0oL4jnwji8FSZstpmiYXjsXNNi/IV Dv/cUuI1mjRSS2EcHX45ld+wIvsRb/Hq+NQHrkhWHZMfQMqOD12Ls4d4cdlCDYgWFzhK E9sQ== 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 33-v6si14067893ply.251.2018.10.01.13.28.26; Mon, 01 Oct 2018 13:28:41 -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 S1726679AbeJBDHl (ORCPT + 99 others); Mon, 1 Oct 2018 23:07:41 -0400 Received: from mga05.intel.com ([192.55.52.43]:21290 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726521AbeJBDHg (ORCPT ); Mon, 1 Oct 2018 23:07:36 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 01 Oct 2018 13:28:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,328,1534834800"; d="scan'208";a="79022373" Received: from maru.jf.intel.com ([10.54.51.77]) by orsmga006.jf.intel.com with ESMTP; 01 Oct 2018 13:27:52 -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 Cc: Jarkko Nikula , James Feist , Vernon Mauery , Jae Hyun Yoo Subject: [PATCH i2c-next v4 3/3] i2c: aspeed: Add bus idle waiting logic for multi-master use cases Date: Mon, 1 Oct 2018 13:27:48 -0700 Message-Id: <20181001202748.8030-4-jae.hyun.yoo@linux.intel.com> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181001202748.8030-1-jae.hyun.yoo@linux.intel.com> References: <20181001202748.8030-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 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 state corruption in the case, this patch adds checking code if any slave operation is ongoing and it waits up to the timeout duration before starting a master_xfer operation. Since the BUSY bit in the I2CD14 register doesn't cover the whole slave sequence, it uses 'Transfer Mode State Machine' bit fields to make up the problem of the BUSY bit. Signed-off-by: Jae Hyun Yoo --- drivers/i2c/busses/i2c-aspeed.c | 62 +++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 6d31f54a6653..edb1944c867b 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 @@ -99,6 +100,7 @@ ASPEED_I2CD_INTR_TX_ACK) /* 0x14 : I2CD Command/Status Register */ +#define ASPEED_I2CD_XFER_MODE_STS_MASK GENMASK(22, 19) #define ASPEED_I2CD_SCL_LINE_STS BIT(18) #define ASPEED_I2CD_SDA_LINE_STS BIT(17) #define ASPEED_I2CD_BUS_BUSY_STS BIT(16) @@ -115,6 +117,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 +161,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 +603,50 @@ 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) +{ + u32 status_check_mask = ASPEED_I2CD_BUS_BUSY_STS; + ktime_t timeout; + + if (bus->multi_master) { + might_sleep(); + timeout = ktime_add_ms(ktime_get(), + jiffies_to_msecs(bus->adap.timeout)); + /* + * ASPEED_I2CD_XFER_MODE_STS_MASK is marked as + * 'for debugging purpose only' in datasheet but ASPEED + * confirmed that this reflects real information and good to be + * used in practical code. It will be used only in multi-master + * use cases. + */ + status_check_mask |= ASPEED_I2CD_XFER_MODE_STS_MASK; + } + + for (;;) { + if (!(readl(bus->base + ASPEED_I2C_CMD_REG) & + status_check_mask)) + 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 +857,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.0