linux/drivers/i2c
Paul Osmialowski 6b07589d8b i2c: s3c2410: fix ABBA deadlock by keeping clock prepared
commit 34e81ad5f0 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
held.

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@samsung.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
History 2015-02-04 10:58:11 +00:00
..
algos Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux 2014-01-29 19:56:20 -08:00
busses i2c: s3c2410: fix ABBA deadlock by keeping clock prepared 2015-02-04 10:58:11 +00:00
muxes i2c: mux: pca954x: fix dependencies 2014-06-27 14:27:19 +02:00
i2c-boardinfo.c i2c: Update the FSF address 2012-03-26 21:47:19 +02:00
i2c-core.c i2c: core: Dispose OF IRQ mapping at client removal time 2014-11-14 15:20:01 +00:00
i2c-core.h i2c: Update the FSF address 2012-03-26 21:47:19 +02:00
i2c-dev.c i2c: i2c-dev: Create 'name' attribute automatically 2013-09-30 06:02:31 +02:00
i2c-mux.c i2c: mux: Inherit retry count and timeout from parent for muxed bus 2013-12-12 22:39:28 +01:00
i2c-smbus.c Update Jean Delvare's e-mail address 2014-01-29 20:40:08 +01:00
i2c-stub.c Update Jean Delvare's e-mail address 2014-01-29 20:40:08 +01:00
Kconfig Remove GENERIC_HARDIRQ config option 2013-09-13 15:09:52 +02:00
Makefile i2c-stub: Move to drivers/i2c 2012-10-28 21:37:00 +01:00