[3.19.y-ckt stable] Patch "i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared" has been added to the 3.19.y-ckt tree

Kamal Mostafa kamal at canonical.com
Tue May 10 00:03:00 UTC 2016


This is a note to let you know that I have just added a patch titled

    i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock prepared

to the linux-3.19.y-queue branch of the 3.19.y-ckt extended stable tree 
which can be found at:

    https://git.launchpad.net/~canonical-kernel/linux/+git/linux-stable-ckt/log/?h=linux-3.19.y-queue

This patch is scheduled to be released in version 3.19.8-ckt21.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.19.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

---8<------------------------------------------------------------

>From f9c431539137dee7f75b5d44c378bf32d8dff3a0 Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javier at osg.samsung.com>
Date: Sat, 16 Apr 2016 21:14:52 -0400
Subject: i2c: exynos5: Fix possible ABBA deadlock by keeping I2C clock
 prepared

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 <linux.amoon at gmail.com>
Signed-off-by: Javier Martinez Canillas <javier at osg.samsung.com>
Reviewed-by: Anand Moon <linux.amoon at gmail.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski at samsung.com>
Signed-off-by: Wolfram Sang <wsa at the-dreams.de>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
---
 drivers/i2c/busses/i2c-exynos5.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index b29c750..f54ece8 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -671,7 +671,9 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
 		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);
@@ -695,7 +697,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
 	}

  out:
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	return ret;
 }

@@ -747,7 +749,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
 		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);
@@ -799,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;
@@ -810,6 +818,8 @@ static int exynos5_i2c_remove(struct platform_device *pdev)

 	i2c_del_adapter(&i2c->adap);

+	clk_unprepare(i2c->clk);
+
 	return 0;
 }

@@ -821,6 +831,8 @@ static int exynos5_i2c_suspend_noirq(struct device *dev)

 	i2c->suspended = 1;

+	clk_unprepare(i2c->clk);
+
 	return 0;
 }

@@ -830,7 +842,9 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
 	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) {
@@ -839,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;
--
2.7.4





More information about the kernel-team mailing list