mirror of https://github.com/hak5/openwrt.git
87 lines
2.6 KiB
Diff
87 lines
2.6 KiB
Diff
From f5913e137c3dac4972ac0ddd5f248924d02d3dcb Mon Sep 17 00:00:00 2001
|
|
From: Varadarajan Narayanan <varada@codeaurora.org>
|
|
Date: Wed, 25 May 2016 13:40:03 +0530
|
|
Subject: [PATCH 14/69] spi: qup: Fix sg nents calculation
|
|
|
|
lib/scatterlist.c:sg_nents_for_len() returns the number of SG
|
|
entries that total up to greater than or equal to the given
|
|
length. However, the spi-qup driver assumed that the returned
|
|
nents is for a total less than or equal to the given length. The
|
|
spi-qup driver requests nents for SPI_MAX_XFER, however the API
|
|
returns nents for SPI_MAX_XFER+delta (actually SZ_64K).
|
|
|
|
Based on this, spi_qup_do_dma() calculates n_words and programs
|
|
that into QUP_MX_{IN|OUT}PUT_CNT register. The calculated
|
|
n_words value is more than the maximum value that can fit in the
|
|
the 16-bit COUNT field of the QUP_MX_{IN|OUT}PUT_CNT register.
|
|
And, the field gets programmed to zero. Since the COUNT field is
|
|
zero, the i/o doesn't start eventually resulting in the i/o
|
|
timing out.
|
|
|
|
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
|
|
---
|
|
drivers/spi/spi-qup.c | 38 ++++++++++++++++++++++++++++++++++++--
|
|
1 file changed, 36 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/spi/spi-qup.c
|
|
+++ b/drivers/spi/spi-qup.c
|
|
@@ -581,6 +581,38 @@ static unsigned int spi_qup_sgl_get_size
|
|
return length;
|
|
}
|
|
|
|
+/**
|
|
+ * spi_qup_sg_nents_for_len - return total count of entries in scatterlist
|
|
+ * needed to satisfy the supplied length
|
|
+ * @sg: The scatterlist
|
|
+ * @len: The total required length
|
|
+ *
|
|
+ * Description:
|
|
+ * Determines the number of entries in sg that sum upto a maximum of
|
|
+ * the supplied length, taking into acount chaining as well
|
|
+ *
|
|
+ * Returns:
|
|
+ * the number of sg entries needed, negative error on failure
|
|
+ *
|
|
+ **/
|
|
+int spi_qup_sg_nents_for_len(struct scatterlist *sg, u64 len)
|
|
+{
|
|
+ int nents;
|
|
+ u64 total;
|
|
+
|
|
+ if (!len)
|
|
+ return 0;
|
|
+
|
|
+ for (nents = 0, total = 0; sg; sg = sg_next(sg)) {
|
|
+ nents++;
|
|
+ total += sg_dma_len(sg);
|
|
+ if (total > len)
|
|
+ return (nents - 1);
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
|
unsigned long timeout)
|
|
{
|
|
@@ -597,7 +629,8 @@ unsigned long timeout)
|
|
int rx_nents = 0, tx_nents = 0;
|
|
|
|
if (rx_sgl) {
|
|
- rx_nents = sg_nents_for_len(rx_sgl, SPI_MAX_XFER);
|
|
+ rx_nents = spi_qup_sg_nents_for_len(rx_sgl,
|
|
+ SPI_MAX_XFER);
|
|
if (rx_nents < 0)
|
|
rx_nents = sg_nents(rx_sgl);
|
|
|
|
@@ -606,7 +639,8 @@ unsigned long timeout)
|
|
}
|
|
|
|
if (tx_sgl) {
|
|
- tx_nents = sg_nents_for_len(tx_sgl, SPI_MAX_XFER);
|
|
+ tx_nents = spi_qup_sg_nents_for_len(tx_sgl,
|
|
+ SPI_MAX_XFER);
|
|
if (tx_nents < 0)
|
|
tx_nents = sg_nents(tx_sgl);
|
|
|