diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2015-08-16 23:52:54 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-09-17 07:13:40 -0400 |
commit | c15f6ed3a18f10cdc33f64906ab353f17a6df114 (patch) | |
tree | d31632b7d325d16e602437062832c01eabae2451 | |
parent | 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff) |
spi: bitbang: Replace spinlock by mutex
chipselect (in the case of spi-gpio: spi_gpio_chipselect, which
calls gpiod_set_raw_value_cansleep) can sleep, so we should not
hold a spinlock while calling it from spi_bitbang_setup.
This issue was introduced by this commit, which converted spi-gpio
to cansleep variants:
d9dda5a191 "spi: spi-gpio: Use 'cansleep' variants to access GPIO"
Replacing the lock variable by a mutex fixes the issue: This is
safe as all instances where the lock is used are called from
contexts that can sleep.
Finally, update spi-ppc4xx and and spi-s3c24xx to use mutex
functions, as they directly hold the lock for similar purpose.
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi-bitbang.c | 17 | ||||
-rw-r--r-- | drivers/spi/spi-ppc4xx.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-s3c24xx.c | 4 | ||||
-rw-r--r-- | include/linux/spi/spi_bitbang.h | 2 |
4 files changed, 12 insertions, 15 deletions
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 840a4984d365..ef43ef507c9a 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c | |||
@@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi) | |||
180 | { | 180 | { |
181 | struct spi_bitbang_cs *cs = spi->controller_state; | 181 | struct spi_bitbang_cs *cs = spi->controller_state; |
182 | struct spi_bitbang *bitbang; | 182 | struct spi_bitbang *bitbang; |
183 | unsigned long flags; | ||
184 | 183 | ||
185 | bitbang = spi_master_get_devdata(spi->master); | 184 | bitbang = spi_master_get_devdata(spi->master); |
186 | 185 | ||
@@ -210,12 +209,12 @@ int spi_bitbang_setup(struct spi_device *spi) | |||
210 | */ | 209 | */ |
211 | 210 | ||
212 | /* deselect chip (low or high) */ | 211 | /* deselect chip (low or high) */ |
213 | spin_lock_irqsave(&bitbang->lock, flags); | 212 | mutex_lock(&bitbang->lock); |
214 | if (!bitbang->busy) { | 213 | if (!bitbang->busy) { |
215 | bitbang->chipselect(spi, BITBANG_CS_INACTIVE); | 214 | bitbang->chipselect(spi, BITBANG_CS_INACTIVE); |
216 | ndelay(cs->nsecs); | 215 | ndelay(cs->nsecs); |
217 | } | 216 | } |
218 | spin_unlock_irqrestore(&bitbang->lock, flags); | 217 | mutex_unlock(&bitbang->lock); |
219 | 218 | ||
220 | return 0; | 219 | return 0; |
221 | } | 220 | } |
@@ -255,13 +254,12 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) | |||
255 | static int spi_bitbang_prepare_hardware(struct spi_master *spi) | 254 | static int spi_bitbang_prepare_hardware(struct spi_master *spi) |
256 | { | 255 | { |
257 | struct spi_bitbang *bitbang; | 256 | struct spi_bitbang *bitbang; |
258 | unsigned long flags; | ||
259 | 257 | ||
260 | bitbang = spi_master_get_devdata(spi); | 258 | bitbang = spi_master_get_devdata(spi); |
261 | 259 | ||
262 | spin_lock_irqsave(&bitbang->lock, flags); | 260 | mutex_lock(&bitbang->lock); |
263 | bitbang->busy = 1; | 261 | bitbang->busy = 1; |
264 | spin_unlock_irqrestore(&bitbang->lock, flags); | 262 | mutex_unlock(&bitbang->lock); |
265 | 263 | ||
266 | return 0; | 264 | return 0; |
267 | } | 265 | } |
@@ -378,13 +376,12 @@ static int spi_bitbang_transfer_one(struct spi_master *master, | |||
378 | static int spi_bitbang_unprepare_hardware(struct spi_master *spi) | 376 | static int spi_bitbang_unprepare_hardware(struct spi_master *spi) |
379 | { | 377 | { |
380 | struct spi_bitbang *bitbang; | 378 | struct spi_bitbang *bitbang; |
381 | unsigned long flags; | ||
382 | 379 | ||
383 | bitbang = spi_master_get_devdata(spi); | 380 | bitbang = spi_master_get_devdata(spi); |
384 | 381 | ||
385 | spin_lock_irqsave(&bitbang->lock, flags); | 382 | mutex_lock(&bitbang->lock); |
386 | bitbang->busy = 0; | 383 | bitbang->busy = 0; |
387 | spin_unlock_irqrestore(&bitbang->lock, flags); | 384 | mutex_unlock(&bitbang->lock); |
388 | 385 | ||
389 | return 0; | 386 | return 0; |
390 | } | 387 | } |
@@ -427,7 +424,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) | |||
427 | if (!master || !bitbang->chipselect) | 424 | if (!master || !bitbang->chipselect) |
428 | return -EINVAL; | 425 | return -EINVAL; |
429 | 426 | ||
430 | spin_lock_init(&bitbang->lock); | 427 | mutex_init(&bitbang->lock); |
431 | 428 | ||
432 | if (!master->mode_bits) | 429 | if (!master->mode_bits) |
433 | master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; | 430 | master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; |
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 54fb984a3e17..dd3d0a218d8b 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c | |||
@@ -210,12 +210,12 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) | |||
210 | if (in_8(&hw->regs->cdm) != cdm) | 210 | if (in_8(&hw->regs->cdm) != cdm) |
211 | out_8(&hw->regs->cdm, cdm); | 211 | out_8(&hw->regs->cdm, cdm); |
212 | 212 | ||
213 | spin_lock(&hw->bitbang.lock); | 213 | mutex_lock(&hw->bitbang.lock); |
214 | if (!hw->bitbang.busy) { | 214 | if (!hw->bitbang.busy) { |
215 | hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); | 215 | hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); |
216 | /* Need to ndelay here? */ | 216 | /* Need to ndelay here? */ |
217 | } | 217 | } |
218 | spin_unlock(&hw->bitbang.lock); | 218 | mutex_unlock(&hw->bitbang.lock); |
219 | 219 | ||
220 | return 0; | 220 | return 0; |
221 | } | 221 | } |
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index f36bc320a807..4e7d1bfed7e6 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c | |||
@@ -198,12 +198,12 @@ static int s3c24xx_spi_setup(struct spi_device *spi) | |||
198 | if (ret) | 198 | if (ret) |
199 | return ret; | 199 | return ret; |
200 | 200 | ||
201 | spin_lock(&hw->bitbang.lock); | 201 | mutex_lock(&hw->bitbang.lock); |
202 | if (!hw->bitbang.busy) { | 202 | if (!hw->bitbang.busy) { |
203 | hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); | 203 | hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); |
204 | /* need to ndelay for 0.5 clocktick ? */ | 204 | /* need to ndelay for 0.5 clocktick ? */ |
205 | } | 205 | } |
206 | spin_unlock(&hw->bitbang.lock); | 206 | mutex_unlock(&hw->bitbang.lock); |
207 | 207 | ||
208 | return 0; | 208 | return 0; |
209 | } | 209 | } |
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index 85578d4be034..154788ed218c 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <linux/workqueue.h> | 4 | #include <linux/workqueue.h> |
5 | 5 | ||
6 | struct spi_bitbang { | 6 | struct spi_bitbang { |
7 | spinlock_t lock; | 7 | struct mutex lock; |
8 | u8 busy; | 8 | u8 busy; |
9 | u8 use_dma; | 9 | u8 use_dma; |
10 | u8 flags; /* extra spi->mode support */ | 10 | u8 flags; /* extra spi->mode support */ |