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

From: Vitaly Wool
Date: Tue Dec 13 2005 - 11:52:04 EST


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 <vwool@xxxxxxxxxxxxx>
Signed-off-by: Dmitry Pervushin <dpervushin@xxxxxxxxx>

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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/