| From ab99e4b2de2efb537f490ef43f896b92dd6be5d2 Mon Sep 17 00:00:00 2001 |
| From: Christian Eggers <ceggers@arri.de> |
| Date: Tue, 28 Jul 2020 12:08:32 +0200 |
| Subject: [PATCH] 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c |
| index 4c13eb715a2b..c62576ce2a88 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; |
| -- |
| 2.27.0 |
| |