summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Eggers <ceggers@arri.de>2020-07-28 12:08:32 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-08-19 08:16:25 +0200
commit7ebb8fd40256e4b661b5d3a38fbbf4c404205fc5 (patch)
tree88d7bb4d71c6ff9214361aee16fdd65856be6dff
parente02c77edd9b015ab49d3ac882c9dd70103a8151b (diff)
downloadlinux-7ebb8fd40256e4b661b5d3a38fbbf4c404205fc5.tar.gz
linux-7ebb8fd40256e4b661b5d3a38fbbf4c404205fc5.tar.bz2
linux-7ebb8fd40256e4b661b5d3a38fbbf4c404205fc5.zip
spi: spidev: Align buffers for DMA
commit aa9e862d7d5bcecd4dca9f39e8b684b93dd84ee7 upstream. Simply copying all xfers from userspace into one bounce buffer causes alignment problems if the SPI controller uses DMA. Ensure that all transfer data blocks within the rx and tx bounce buffers are aligned for DMA (according to ARCH_KMALLOC_MINALIGN). Alignment may increase the usage of the bounce buffers. In some cases, the buffers may need to be increased using the "bufsiz" module parameter. Signed-off-by: Christian Eggers <ceggers@arri.de> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200728100832.24788-1-ceggers@arri.de Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/spi/spidev.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index ac6bf1fbbfe6..be503a0e6ef7 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -223,6 +223,11 @@ static int spidev_message(struct spidev_data *spidev,
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
+ /* Ensure that also following allocations from rx_buf/tx_buf will meet
+ * DMA alignment requirements.
+ */
+ unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN);
+
k_tmp->len = u_tmp->len;
total += k_tmp->len;
@@ -238,17 +243,17 @@ static int spidev_message(struct spidev_data *spidev,
if (u_tmp->rx_buf) {
/* this transfer needs space in RX bounce buffer */
- rx_total += k_tmp->len;
+ rx_total += len_aligned;
if (rx_total > bufsiz) {
status = -EMSGSIZE;
goto done;
}
k_tmp->rx_buf = rx_buf;
- rx_buf += k_tmp->len;
+ rx_buf += len_aligned;
}
if (u_tmp->tx_buf) {
/* this transfer needs space in TX bounce buffer */
- tx_total += k_tmp->len;
+ tx_total += len_aligned;
if (tx_total > bufsiz) {
status = -EMSGSIZE;
goto done;
@@ -258,7 +263,7 @@ static int spidev_message(struct spidev_data *spidev,
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
- tx_buf += k_tmp->len;
+ tx_buf += len_aligned;
}
k_tmp->cs_change = !!u_tmp->cs_change;
@@ -290,16 +295,16 @@ static int spidev_message(struct spidev_data *spidev,
goto done;
/* copy any rx data out of bounce buffer */
- rx_buf = spidev->rx_buffer;
- for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
+ for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
+ n;
+ n--, k_tmp++, u_tmp++) {
if (u_tmp->rx_buf) {
if (copy_to_user((u8 __user *)
- (uintptr_t) u_tmp->rx_buf, rx_buf,
+ (uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
- rx_buf += u_tmp->len;
}
}
status = total;