From patchwork Sun Apr 17 01:14:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Martinez Canillas X-Patchwork-Id: 8862341 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 8E538BF29F for ; Sun, 17 Apr 2016 01:15:44 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AC0D6201C0 for ; Sun, 17 Apr 2016 01:15:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AA056201B4 for ; Sun, 17 Apr 2016 01:15:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752318AbcDQBP0 (ORCPT ); Sat, 16 Apr 2016 21:15:26 -0400 Received: from lists.s-osg.org ([54.187.51.154]:48808 "EHLO lists.s-osg.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752295AbcDQBPZ (ORCPT ); Sat, 16 Apr 2016 21:15:25 -0400 Received: from localhost.localdomain.localdomain (host-64.58.217.201.copaco.com.py [201.217.58.64]) by lists.s-osg.org (Postfix) with ESMTPSA id B9A21E2897; Sun, 17 Apr 2016 01:15:20 +0000 (UTC) From: Javier Martinez Canillas To: linux-kernel@vger.kernel.org Cc: Anand Moon , Javier Martinez Canillas , Kukjin Kim , linux-samsung-soc@vger.kernel.org, Wolfram Sang , Krzysztof Kozlowski , linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v2 2/2] i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared Date: Sat, 16 Apr 2016 21:14:53 -0400 Message-Id: <1460855693-28225-2-git-send-email-javier@osg.samsung.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1460855693-28225-1-git-send-email-javier@osg.samsung.com> References: <1460855693-28225-1-git-send-email-javier@osg.samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The exynos5 I2C controller driver always prepares and enables a clock before using it and then disables unprepares it when the clock is not used anymore. But this can cause a possible ABBA deadlock in some scenarios since a driver that uses regmap to access its I2C registers, will first grab the regmap lock and then the I2C xfer function will grab the prepare lock when preparing the I2C clock. But since the clock driver also uses regmap for I2C accesses, preparing a clock will first grab the prepare lock and then the regmap lock when using the regmap API. An example of this happens on the Exynos5422 Odroid XU4 board where a s2mps11 PMIC is used and both the s2mps11 regulators and clk drivers share the same I2C regmap. The possible deadlock is reported by the kernel lockdep: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(sec_core:428:(regmap)->lock); lock(prepare_lock); lock(sec_core:428:(regmap)->lock); lock(prepare_lock); *** DEADLOCK *** Fix it by leaving the code prepared on probe and use {en,dis}able in the I2C transfer function. This patch is similar to commit 34e81ad5f0b6 ("i2c: s3c2410: fix ABBA deadlock by keeping clock prepared") that fixes the same bug in other driver for an I2C controller found in Samsung SoCs. Reported-by: Anand Moon Signed-off-by: Javier Martinez Canillas Reviewed-by: Anand Moon Tested-by: Anand Moon Reviewed-by: Krzysztof Kozlowski --- Changes in v2: - Add Anand Moon's Reviewed and Tested by tags. - Unprepare the clock on suspend. Suggested by Krzysztof Kozlowski. drivers/i2c/busses/i2c-exynos5.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index ebbcba3de20a..f54ece8fce78 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -671,7 +671,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, return -EIO; } - ret = clk_prepare_enable(i2c->clk); + ret = clk_enable(i2c->clk); if (ret) return ret; @@ -697,7 +697,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, } out: - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); return ret; } @@ -803,6 +803,10 @@ static int exynos5_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); + clk_disable(i2c->clk); + + return 0; + err_clk: clk_disable_unprepare(i2c->clk); return ret; @@ -814,6 +818,8 @@ static int exynos5_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); + clk_unprepare(i2c->clk); + return 0; } @@ -825,6 +831,8 @@ static int exynos5_i2c_suspend_noirq(struct device *dev) i2c->suspended = 1; + clk_unprepare(i2c->clk); + return 0; } @@ -845,7 +853,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev) } exynos5_i2c_init(i2c); - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); i2c->suspended = 0; return 0;