[PATCH/RFC] SPI: add DMAUNSAFE analog to David Brownell's core

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings,

this patch removes nasty buffer allocation in spi core for sync message transfers. (And thus solves the problem of possible priority inversion I've pointed out before).
The write_then_read function sets the flags singalling for buffers not being DMA-safe and it's absolutely up to the controller whatta do with that.
I. e. it will prolly allocate/copy if it performs DMA transfers or just don't do anything special if it's working in PIO. It can even use a single DMA-safe buffer as David's core did (although I wouldn't encourage anyone to do that! :))
This is of coure more flexible and also more optimal as it will *not* require _redundant_ memcpy's and semaphores protection in case of PIO transfers.
Please note that this is a key patch for us in some aspects, although it's rather small! :)

Signed-off-by: Vitaly Wool <[email protected]>
Signed-off-by: Dmitry Pervushin <[email protected]>

 drivers/spi/spi.c       |   35 ++++++-----------------------------
 include/linux/spi/spi.h |    7 +++++++
 2 files changed, 13 insertions(+), 29 deletions(-)

Index: linux-2.6.orig/drivers/spi/spi.c
===================================================================
--- linux-2.6.orig.orig/drivers/spi/spi.c
+++ linux-2.6.orig/drivers/spi/spi.c
@@ -507,10 +507,6 @@ int spi_sync(struct spi_device *spi, str
 }
 EXPORT_SYMBOL_GPL(spi_sync);
 
-#define	SPI_BUFSIZ	(SMP_CACHE_BYTES)
-
-static u8	*buf;
-
 /**
  * spi_write_then_read - SPI synchronous write followed by read
  * @spi: device with which data will be exchanged
@@ -532,39 +528,28 @@ int spi_write_then_read(struct spi_devic
 		const u8 *txbuf, unsigned n_tx,
 		u8 *rxbuf, unsigned n_rx)
 {
-	static DECLARE_MUTEX(lock);
-
 	int			status;
 	struct spi_message	message;
 	struct spi_transfer	x[2];
 
-	/* 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.
-	 */
-	if ((n_tx + n_rx) > SPI_BUFSIZ)
-		return -EINVAL;
-
-	down(&lock);
 	memset(x, 0, sizeof x);
+	memset(&message, 0, sizeof message);
 
-	memcpy(buf, txbuf, n_tx);
-	x[0].tx_buf = buf;
+	x[0].tx_buf = tx_buf;
 	x[0].len = n_tx;
+	x[0].tx_dma_unsafe = 1;
 
-	x[1].rx_buf = buf + n_tx;
+	x[1].rx_buf = rx_buf;
 	x[1].len = n_rx;
+	x[1].rx_dma_unsafe = 1;
 
 	/* do the i/o */
 	message.transfers = x;
 	message.n_transfer = ARRAY_SIZE(x);
 	status = spi_sync(spi, &message);
-	if (status == 0) {
-		memcpy(rxbuf, x[1].rx_buf, n_rx);
+	if (status == 0)
 		status = message.status;
-	}
 
-	up(&lock);
 	return status;
 }
 EXPORT_SYMBOL_GPL(spi_write_then_read);
@@ -575,12 +560,6 @@ static int __init spi_init(void)
 {
 	int	status;
 
-	buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
-	if (!buf) {
-		status = -ENOMEM;
-		goto err0;
-	}
-
 	status = bus_register(&spi_bus_type);
 	if (status < 0)
 		goto err1;
@@ -593,9 +572,7 @@ static int __init spi_init(void)
 err2:
 	bus_unregister(&spi_bus_type);
 err1:
-	kfree(buf);
 	buf = NULL;
-err0:
 	return status;
 }
 
Index: linux-2.6.orig/include/linux/spi/spi.h
===================================================================
--- linux-2.6.orig.orig/include/linux/spi/spi.h
+++ linux-2.6.orig/include/linux/spi/spi.h
@@ -248,6 +248,10 @@ extern struct spi_master *spi_busnum_to_
  * @rx_dma: DMA address of buffer, if spi_message.is_dma_mapped
  * @len: size of rx and tx buffers (in bytes)
  * @cs_change: affects chipselect after this transfer completes
+ * @tx_dma_unsafe: signals to controller driver that the buffer
+ * 	is not DMA-safe
+ * @rx_dma_unsafe: signals to controller driver that the buffer
+ * 	is not DMA-safe
  * @delay_usecs: microseconds to delay after this transfer before
  * 	(optionally) changing the chipselect status, then starting
  * 	the next transfer or completing this spi_message.
@@ -288,6 +292,9 @@ struct spi_transfer {
 	dma_addr_t	rx_dma;
 
 	unsigned	cs_change:1;
+	unsigned	rx_dma_unsafe:1;
+	unsigned	tx_dma_unsafe:1;
+
 	u16		delay_usecs;
 };
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux