[patch 2.6.15-rc5-mm2] SPI, priority inversion tweak

From: David Brownell
Date: Tue Dec 13 2005 - 14:04:43 EST


This is an updated version of the patch from Mark Underwood, handling
the no-memory case better and using SLAB_KERNEL not SLAB_ATOMIC.

Please apply it on top of the current SPI code in the MM tree.

- Dave
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.

From: Mark Underwood <basicmark@xxxxxxxxx>
Signed-off-by: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>

--- g26.orig/drivers/spi/spi.c 2005-12-11 11:06:38.000000000 -0800
+++ g26/drivers/spi/spi.c 2005-12-13 09:56:22.000000000 -0800
@@ -541,22 +541,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 */
@@ -568,7 +576,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);