From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1424357AbcFMTIT (ORCPT ); Mon, 13 Jun 2016 15:08:19 -0400 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:43546 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753702AbcFMSh3 (ORCPT ); Mon, 13 Jun 2016 14:37:29 -0400 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Wolfram Sang" , "Javier Martinez Canillas" , "Krzysztof Kozlowski" , "Anand Moon" Date: Mon, 13 Jun 2016 19:36:37 +0100 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.16 042/114] i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared In-Reply-To: X-SA-Exim-Connect-IP: 2a02:8011:400e:2:6f00:88c8:c921:d332 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.36-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Javier Martinez Canillas commit 10ff4c5239a137abfc896ec73ef3d15a0f86a16a upstream. 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 Reviewed-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang Signed-off-by: Ben Hutchings --- drivers/i2c/busses/i2c-exynos5.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -615,7 +615,9 @@ static int exynos5_i2c_xfer(struct i2c_a return -EIO; } - clk_prepare_enable(i2c->clk); + ret = clk_enable(i2c->clk); + if (ret) + return ret; for (i = 0; i < num; i++, msgs++) { stop = (i == num - 1); @@ -639,7 +641,7 @@ static int exynos5_i2c_xfer(struct i2c_a } out: - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); return ret; } @@ -691,7 +693,9 @@ static int exynos5_i2c_probe(struct plat return -ENOENT; } - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->regs = devm_ioremap_resource(&pdev->dev, mem); @@ -742,6 +746,10 @@ static int exynos5_i2c_probe(struct plat platform_set_drvdata(pdev, i2c); + clk_disable(i2c->clk); + + return 0; + err_clk: clk_disable_unprepare(i2c->clk); return ret; @@ -753,6 +761,8 @@ static int exynos5_i2c_remove(struct pla i2c_del_adapter(&i2c->adap); + clk_unprepare(i2c->clk); + return 0; } @@ -764,6 +774,8 @@ static int exynos5_i2c_suspend_noirq(str i2c->suspended = 1; + clk_unprepare(i2c->clk); + return 0; } @@ -773,7 +785,9 @@ static int exynos5_i2c_resume_noirq(stru struct exynos5_i2c *i2c = platform_get_drvdata(pdev); int ret = 0; - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return ret; ret = exynos5_hsi2c_clock_setup(i2c); if (ret) { @@ -782,7 +796,7 @@ static int exynos5_i2c_resume_noirq(stru } exynos5_i2c_init(i2c); - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); i2c->suspended = 0; return 0;