[3.13.y-ckt stable] Patch "i2c: s3c2410: fix ABBA deadlock by keeping clock prepared" has been added to staging queue

Kamal Mostafa kamal at canonical.com
Thu Mar 19 20:21:30 UTC 2015

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

    i2c: s3c2410: fix ABBA deadlock by keeping clock prepared

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


This patch is scheduled to be released in version 3.13.11-ckt17.

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.13.y-ckt tree, see



>From 812a14e853e8cbd0001f1ee9fc680fa3da457ccd Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <p.osmialowsk at samsung.com>
Date: Mon, 19 Jan 2015 17:03:33 +0100
Subject: i2c: s3c2410: fix ABBA deadlock by keeping clock prepared

commit 34e81ad5f0b60007c95995eb7803da7e00c6c611 upstream.

This patch solves deadlock between clock prepare mutex and regmap mutex reported
by Tomasz Figa in [1] by implementing solution from [2]: "always leave the clock
of the i2c controller in a prepared state".

[1] https://lkml.org/lkml/2014/7/2/171
[2] https://lkml.org/lkml/2014/7/2/207

On each i2c transfer handled by s3c24xx_i2c_xfer(), clk_prepare_enable() was
called, which calls clk_prepare() then clk_enable(). clk_prepare() takes
prepare_lock mutex before proceeding. Note that i2c transfer functions are
invoked from many places in kernel, typically with some other additional lock

It may happen that function on CPU1 (e.g. regmap_update_bits()) has taken a
mutex (i.e. regmap lock mutex) then it attempts i2c communication in order to
proceed (so it needs to obtain clock related prepare_lock mutex during transfer
preparation stage due to clk_prepare() call). At the same time other task on
CPU0 wants to operate on clock (e.g. to (un)prepare clock for some other reason)
so it has taken prepare_lock mutex.

CPU0:                        CPU1:
clk_disable_unused()         regulator_disable()
  clk_prepare_lock()           map->lock(map->lock_arg)
  regmap_read()                s3c24xx_i2c_xfer()
    map->lock(map->lock_arg)     clk_prepare_lock()

Implemented solution from [2] leaves i2c clock prepared. Preparation is done in
s3c24xx_i2c_probe() function. Without this patch, it is immediately unprepared
by clk_disable_unprepare() call. I've replaced this call with clk_disable() and
I've added clk_unprepare() call in s3c24xx_i2c_remove().

The s3c24xx_i2c_xfer() function now uses clk_enable() instead of
clk_prepare_enable() (and clk_disable() instead of clk_unprepare_disable()).

Signed-off-by: Paul Osmialowski <p.osmialowsk at samsung.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski at samsung.com>
Signed-off-by: Wolfram Sang <wsa at the-dreams.de>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
 drivers/i2c/busses/i2c-s3c2410.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 2729e40..dcadbf3 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -712,14 +712,16 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
 	int ret;

-	clk_prepare_enable(i2c->clk);
+	ret = clk_enable(i2c->clk);
+	if (ret)
+		return ret;

 	for (retry = 0; retry < adap->retries; retry++) {

 		ret = s3c24xx_i2c_doxfer(i2c, msgs, num);

 		if (ret != -EAGAIN) {
-			clk_disable_unprepare(i2c->clk);
+			clk_disable(i2c->clk);
 			return ret;
@@ -729,7 +731,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,

-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	return -EREMOTEIO;
@@ -1109,7 +1111,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)

 	ret = s3c24xx_i2c_init(i2c);
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "I2C controller init failed\n");
 		return ret;
@@ -1121,6 +1123,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 	i2c->irq = ret = platform_get_irq(pdev, 0);
 	if (ret <= 0) {
 		dev_err(&pdev->dev, "cannot find IRQ\n");
+		clk_unprepare(i2c->clk);
 		return ret;

@@ -1129,12 +1132,14 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)

 	if (ret != 0) {
 		dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+		clk_unprepare(i2c->clk);
 		return ret;

 	ret = s3c24xx_i2c_register_cpufreq(i2c);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+		clk_unprepare(i2c->clk);
 		return ret;

@@ -1151,6 +1156,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		clk_unprepare(i2c->clk);
 		return ret;

@@ -1172,6 +1178,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);

+	clk_unprepare(i2c->clk);

@@ -1200,10 +1208,13 @@ static int s3c24xx_i2c_resume(struct device *dev)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+	int ret;

-	clk_prepare_enable(i2c->clk);
+	ret = clk_enable(i2c->clk);
+	if (ret)
+		return ret;
-	clk_disable_unprepare(i2c->clk);
+	clk_disable(i2c->clk);
 	i2c->suspended = 0;

 	return 0;

More information about the kernel-team mailing list