diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f1217ae59f3d..22c71e238fdf 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1545,12 +1545,18 @@ int spi_write_then_read(struct spi_device *spi, 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 ... + /* Use preallocated DMA-safe buffer if we can. We can't avoid + * copying here, (as a pure convenience thing), but we can + * keep heap costs out of the hot path unless someone else is + * using the pre-allocated buffer or the transfer is too large. */ - if ((n_tx + n_rx) > SPI_BUFSIZ) - return -EINVAL; + if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) { + local_buf = kmalloc(max(SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL); + if (!local_buf) + return -ENOMEM; + } else { + local_buf = buf; + } spi_message_init(&message); memset(x, 0, sizeof x); @@ -1563,14 +1569,6 @@ int spi_write_then_read(struct spi_device *spi, spi_message_add_tail(&x[1], &message); } - /* ... unless someone else is using the pre-allocated buffer */ - if (!mutex_trylock(&lock)) { - local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); - if (!local_buf) - return -ENOMEM; - } else - local_buf = buf; - memcpy(local_buf, txbuf, n_tx); x[0].tx_buf = local_buf; x[1].rx_buf = local_buf + n_tx;