From patchwork Thu Nov 15 12:13:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naveen Krishna Chatradhi X-Patchwork-Id: 1748771 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 9F505DF230 for ; Thu, 15 Nov 2012 11:57:07 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TYy29-0007ZQ-4h; Thu, 15 Nov 2012 11:55:01 +0000 Received: from mailout3.samsung.com ([203.254.224.33]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TYy1z-0007Uj-NP for linux-arm-kernel@lists.infradead.org; Thu, 15 Nov 2012 11:54:53 +0000 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MDJ00KVG2EJIVA0@mailout3.samsung.com> for linux-arm-kernel@lists.infradead.org; Thu, 15 Nov 2012 20:54:49 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [172.20.52.124]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id A8.10.01231.908D4A05; Thu, 15 Nov 2012 20:54:49 +0900 (KST) X-AuditID: cbfee61a-b7fa66d0000004cf-11-50a4d809bcff Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 18.10.01231.808D4A05; Thu, 15 Nov 2012 20:54:49 +0900 (KST) Received: from localhost.localdomain ([107.108.73.106]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MDJ0033F28S3800@mmp1.samsung.com> for linux-arm-kernel@lists.infradead.org; Thu, 15 Nov 2012 20:54:48 +0900 (KST) From: Naveen Krishna Chatradhi To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-i2c@vger.kernel.org Subject: [PATCH 3/4] i2c-s3c2410: use exponential back off while polling for bus idle Date: Thu, 15 Nov 2012 17:43:32 +0530 Message-id: <1352981613-2098-4-git-send-email-ch.naveen@samsung.com> X-Mailer: git-send-email 1.7.0.4 In-reply-to: <1352981613-2098-1-git-send-email-ch.naveen@samsung.com> References: <1352981613-2098-1-git-send-email-ch.naveen@samsung.com> DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrLLMWRmVeSWpSXmKPExsWyRsSkRpfzxpIAgzNfBS02Pb7G6sDosXlJ fQBjFJdNSmpOZllqkb5dAlfG5O+3mAvuKFasOr6PtYHxp1QXIyeHhICJxOGXC5kgbDGJC/fW s3UxcnEICSxllHj4ookRpuhC20ZGiMQiRol1jddZIJwNTBKnJu9lA6liEzCTOLhoNTuILSKQ IbHk0QawDmaBXkaJbf8egCWEBcIl3k88BGazCKhKvGx6wQpi8wq4SHT/v8ACsU5BonUZRA2n gKvE9qVHwc4QAqrZfXElK0SvgMS3yYeA6jmA6mUlNh1gBtklIXCZTWLZyi1Q/0hKHFxxg2UC o/ACRoZVjKKpBckFxUnpuYZ6xYm5xaV56XrJ+bmbGIFhePrfM6kdjCsbLA4xCnAwKvHwOvxY HCDEmlhWXJl7iFGCg1lJhNfg3JIAId6UxMqq1KL8+KLSnNTiQ4w+QJdMZJYSTc4HxkheSbyh sYm5qbGppZGRmakpDmElcd5mj5QAIYH0xJLU7NTUgtQimHFMHJxSDYzyxket36+df930gobx h1RNSZt4t/TC5E8nVjX8Zq552JAnskphcWdh92uRhuN5nrcMf53xDXigsH+VgCFH4byMTfvW fUo8cTRZY80yhUkzj0yv9Dr4mPFXLvusq7GJAktLP4htsFsz9Uo1t9qsXPm77t+FeY0vPoq8 EKzx4NrDI/8r9irbfTJWYinOSDTUYi4qTgQARBQwZ3ACAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFuphkeLIzCtJLcpLzFFi42I5/e+xgC7njSUBBh8Os1psenyN1YHRY/OS +gDGqAZGm4zUxJTUIoXUvOT8lMy8dFsl7+B453hTMwNDXUNLC3MlhbzE3FRbJRefAF23zByg qUoKZYk5pUChgMTiYiV9O0wTQkPcdC1gGiN0fUOC4HqMDNBAwhrGjMnfbzEX3FGsWHV8H2sD 40+pLkZODgkBE4kLbRsZIWwxiQv31rN1MXJxCAksYpRY13idBcLZwCRxavJeNpAqNgEziYOL VrOD2CICGRJLHm1gBCliFuhllNj27wFYQlggXOL9xENgNouAqsTLphesIDavgItE9/8LLBDr FCRal0HUcAq4SmxfehTsDCGgmt0XV7JOYORdwMiwilE0tSC5oDgpPddQrzgxt7g0L10vOT93 EyM4yJ9J7WBc2WBxiFGAg1GJh9fhx+IAIdbEsuLK3EOMEhzMSiK8BueWBAjxpiRWVqUW5ccX leakFh9i9AG6aiKzlGhyPjAC80riDY1NzE2NTS1NLEzMLHEIK4nzNnukBAgJpCeWpGanphak FsGMY+LglGpgTLLK2e5tf5wnRqv09cQku4+RlW9P+kvF/0ibtbzn9I5nz+YFuGQ8MxXTOVPD XWSwK+h1fUlt+LJL5/6W3X716OtE2fuFPB9YuUxCSgSk5gd9XH2nffE3fdHdC1c5nmW7/3d6 Ar/zstdLS3T+bH5yueSj5Sv5R/Nrnx5aa3bcdObijTmFzd07BJRYijMSDbWYi4oTAfUVaVCf AgAA X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121115_065452_471423_DFB3397B X-CRM114-Status: GOOD ( 17.58 ) X-Spam-Score: -7.6 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [203.254.224.33 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: kgene.kim@samsung.com, w.sang@pengutronix.de, djkurtz@chromium.org, ben-linux@fluff.org, khali@linux-fr.org, naveenkrishna.ch@gmail.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Daniel Kurtz Usually, the i2c controller has finished emitting the i2c STOP before the driver reaches the bus idle polling loop. Optimize for this most common case by reading IICSTAT first and potentially skipping the loop. If the cpu is faster than the hardware, we wait for bus idle in a polling loop. However, since the duration of one iteration of the loop is dependent on cpu freq, and this i2c IP is used on many different systems, use a time based loop timeout (5 ms). We would like very low latencies to detect bus idle for the normal 'fast' case. However, if a device is slow to release the bus for some reason, it could hold off the STOP generation for up to several milliseconds. Rapidly polling for bus idle would seriously load the CPU while waiting for it to release the bus. So, use a partial exponential backoff as a compromise between idle detection latency and cpu load. Signed-off-by: Daniel Kurtz Cc: Olof Johansson Cc: Benson Leung Cc: Doug Anderson Cc: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi --- drivers/i2c/busses/i2c-s3c2410.c | 67 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index fc4bf35..362a307 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -49,6 +49,9 @@ #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) +/* Max time to wait for bus to become idle after a xfer (in us) */ +#define S3C2410_IDLE_TIMEOUT 5000 + /* i2c controller state */ enum s3c24xx_i2c_state { STATE_IDLE, @@ -556,6 +559,48 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) return -ETIMEDOUT; } +/* s3c24xx_i2c_wait_idle + * + * wait for the i2c bus to become idle. +*/ + +static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) +{ + unsigned long iicstat; + ktime_t start, now; + unsigned long delay; + + /* ensure the stop has been through the bus */ + + dev_dbg(i2c->dev, "waiting for bus idle\n"); + + start = now = ktime_get(); + + /* + * Most of the time, the bus is already idle within a few usec of the + * end of a transaction. However, really slow i2c devices can stretch + * the clock, delaying STOP generation. + * + * As a compromise between idle detection latency for the normal, fast + * case, and system load in the slow device case, use an exponential + * back off in the polling loop, up to 1/10th of the total timeout, + * then continue to poll at a constant rate up to the timeout. + */ + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + delay = 1; + while ((iicstat & S3C2410_IICSTAT_START) && + ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) { + usleep_range(delay, 2 * delay); + if (delay < S3C2410_IDLE_TIMEOUT / 10) + delay <<= 1; + now = ktime_get(); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + if (iicstat & S3C2410_IICSTAT_START) + dev_warn(i2c->dev, "timeout waiting for bus idle\n"); +} + /* s3c24xx_i2c_doxfer * * this starts an i2c transfer @@ -564,8 +609,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long iicstat, timeout; - int spins = 20; + unsigned long timeout; int ret; if (i2c->suspended) @@ -603,24 +647,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, if (i2c->quirks & QUIRK_HDMIPHY) goto out; - /* ensure the stop has been through the bus */ - - dev_dbg(i2c->dev, "waiting for bus idle\n"); - - /* first, try busy waiting briefly */ - do { - cpu_relax(); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } while ((iicstat & S3C2410_IICSTAT_START) && --spins); - - /* if that timed out sleep */ - if (!spins) { - msleep(1); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } - - if (iicstat & S3C2410_IICSTAT_START) - dev_warn(i2c->dev, "timeout waiting for bus idle\n"); + s3c24xx_i2c_wait_idle(i2c); out: return ret;