From: Mark Underwood Update the SPI framework to remove a potential priority inversion case by reverting to kmalloc if the pre-allocated DMA-safe buffer isn't available. Signed-off-by: David Brownell Signed-off-by: Andrew Morton --- drivers/spi/spi.c | 24 ++++++++++++++++++------ 1 files changed, 18 insertions(+), 6 deletions(-) diff -puN drivers/spi/spi.c~simple-spi-framework-priority-inversion-tweak drivers/spi/spi.c --- devel/drivers/spi/spi.c~simple-spi-framework-priority-inversion-tweak 2005-12-13 14:40:21.000000000 -0800 +++ devel-akpm/drivers/spi/spi.c 2005-12-13 14:40:28.000000000 -0800 @@ -505,22 +505,30 @@ int spi_write_then_read(struct spi_devic int status; struct spi_message message; struct spi_transfer x[2]; + u8 *local_buf; /* Use preallocated DMA-safe buffer. We can't avoid copying here, * (as a pure convenience thing), but we can keep heap costs - * out of the hot path. + * out of the hot path ... */ if ((n_tx + n_rx) > SPI_BUFSIZ) return -EINVAL; - down(&lock); + /* ... unless someone else is using the pre-allocated buffer */ + if (down_trylock(&lock)) { + local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); + if (!local_buf) + return -ENOMEM; + } else + local_buf = buf; + memset(x, 0, sizeof x); - memcpy(buf, txbuf, n_tx); - x[0].tx_buf = buf; + memcpy(local_buf, txbuf, n_tx); + x[0].tx_buf = local_buf; x[0].len = n_tx; - x[1].rx_buf = buf + n_tx; + x[1].rx_buf = local_buf + n_tx; x[1].len = n_rx; /* do the i/o */ @@ -532,7 +540,11 @@ int spi_write_then_read(struct spi_devic status = message.status; } - up(&lock); + if (x[0].tx_buf == buf) + up(&lock); + else + kfree(local_buf); + return status; } EXPORT_SYMBOL_GPL(spi_write_then_read); _