Skip to contentSkip to conversation

Fixes for Vybrid SPI DMA implementation

PATCH Superseded Sanchayan Maity 3 participants 15 messages Nov 21, 2016 – Nov 22, 2016

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover Fixes for Vybrid SPI DMA implementation

Hello,

The following set of patches have fixes for Vybrid SPI DMA implementation along with some minor clean ups requested at time when v3 version of SPI DMA support patch was accepted.

This series of patches is based on top of branch topic/fsl-dspi.
http://git.kernel.org/cgit/linux/kernel/git/broonie/spi.git/log/?h=topic/fsl-dspi

The patches have been tested on a Toradex Colibri Vybrid VF61 module and now incoporate feedback from Stefan on version 1 of patchset.

Changes since v1:
1. Place the continuous selection format patch second in order and remove code duplication
2. Improve the use of curr_xfer_len and instead of converting from bytes to DMA transfers in every use, do it at a single place. Accordingly change it's use at other places
3. Code cleanup patch has less to clean with change above

v1:
http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1274632.html

Thanks & Regards,
Sanchayan.

Sanchayan Maity (4):
spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE
spi: spi-fsl-dspi: Fix continuous selection format
spi: spi-fsl-dspi: Fix incorrect DMA setup
spi: spi-fsl-dspi: Minor code cleanup and error path fixes

 drivers/spi/spi-fsl-dspi.c | 71 ++++++++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 27 deletions(-)
Signature · 1 line
2.10.2
#1 lore raw

PATCH v2 1/4 spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE

Current DMA implementation had a bug where the DMA transfer would exit the loop in dspi_transfer_one_message after the completion of a single transfer. This results in a multi message transfer submitted with SPI_IOC_MESSAGE to terminate incorrectly without an error.

---
 drivers/spi/spi-fsl-dspi.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/spi/spi-fsl-dspi.c +8 -4
index bc64700..b1ee1f5 100644
@@ -714,7 +714,7 @@ static int dspi_transfer_one_message(struct spi_master *master,
 				SPI_RSER_TFFFE | SPI_RSER_TFFFD |
 				SPI_RSER_RFDFE | SPI_RSER_RFDFD);
 			status = dspi_dma_xfer(dspi);
-			goto out;
+			break;
 		default:
 			dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
 				trans_mode);
@@ -722,9 +722,13 @@ static int dspi_transfer_one_message(struct spi_master *master,
 			goto out;
 		}
 
-		if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
-			dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
-		dspi->waitflags = 0;
+		if (trans_mode != DSPI_DMA_MODE) {
+			if (wait_event_interruptible(dspi->waitq,
+						dspi->waitflags))
+				dev_err(&dspi->pdev->dev,
+					"wait transfer complete fail!\n");
+			dspi->waitflags = 0;
+		}
 
 		if (transfer->delay_usecs)
 			udelay(transfer->delay_usecs);
Signature · 1 line
2.10.2
maintainer
#2 lore raw

Re: [PATCH v2 1/4] spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE

Quoted 4 lines · Sanchayan Maity

Current DMA implementation had a bug where the DMA transfer would exit the loop in dspi_transfer_one_message after the completion of a single transfer. This results in a multi message transfer submitted with SPI_IOC_MESSAGE to terminate incorrectly without an error.

Please don't resend already applied patches. If there are any changes
needed please send incremental changes on top of what's already applied.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161121/59a1e93d/attachment.sig>

#3 lore raw

Re: [PATCH v2 1/4] spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE

Hello Mark,

Quoted 8 lines · Mark Brown
Quoted 4 lines · Sanchayan Maity

Current DMA implementation had a bug where the DMA transfer would exit the loop in dspi_transfer_one_message after the completion of a single transfer. This results in a multi message transfer submitted with SPI_IOC_MESSAGE to terminate incorrectly without an error.

Please don't resend already applied patches. If there are any changes needed please send incremental changes on top of what's already applied.

This is not a resend of an applied patch. The whole series applies on top of your topic/fsl-dspi branch and has fixes for the SPI DMA as incremental changes

- Sanchaya.

#4 lore raw

Re: [PATCH v2 1/4] spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE

Hello Mark,

Quoted 9 lines · maitysanchayan at gmail.com

Hello Mark,

Quoted 6 lines · Mark Brown
Quoted 4 lines · Sanchayan Maity

Current DMA implementation had a bug where the DMA transfer would exit the loop in dspi_transfer_one_message after the completion of a single transfer. This results in a multi message transfer submitted with SPI_IOC_MESSAGE to terminate incorrectly without an error.

Quoted 7 lines
Quoted 2 lines

Please don't resend already applied patches. If there are any changes needed please send incremental changes on top of what's already applied.

This is not a resend of an applied patch. The whole series applies on top of your topic/fsl-dspi branch and has fixes for the SPI DMA as incremental changes

Sorry. I take that back. I now see you applied the patch and I got the applied mail after I replied.

- Sanchayan.

maintainer
#5 lore raw

Re: [PATCH v2 1/4] spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE

Quoted 8 lines · maitysanchayan at gmail.com
Quoted 3 lines · maitysanchayan at gmail.com

This is not a resend of an applied patch. The whole series applies on top of your topic/fsl-dspi branch and has fixes for the SPI DMA as incremental changes

Sorry. I take that back. I now see you applied the patch and I got the applied mail after I replied.

Ah, I did apply it on Friday but somehow it didn't get pushed until
yesterday. Sorry for the confusion.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161122/ce824c66/attachment.sig>

#6 lore raw

PATCH v2 2/4 spi: spi-fsl-dspi: Fix continuous selection format

In reply to Sanchayan Maity

Current DMA implementation was not handling the continuous selection format viz. SPI chip select would be deasserted even between sequential serial transfers. Use the cs_change variable and correctly set or reset the CONT bit accordingly for case where peripherals require the chip select to be asserted between sequential transfers.

---
 drivers/spi/spi-fsl-dspi.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/spi/spi-fsl-dspi.c +2 -0
index b1ee1f5..41422cd 100644
@@ -261,6 +261,8 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
 					SPI_PUSHR_CTAS(0);
+	if (!dspi->cs_change)
+		dspi->dma->tx_dma_buf[i] |= SPI_PUSHR_CONT;
 	dspi->tx += tx_word + 1;
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
Signature · 1 line
2.10.2
#7 lore raw

Re: [PATCH v2 2/4] spi: spi-fsl-dspi: Fix continuous selection format

Quoted 16 lines · Sanchayan Maity

Current DMA implementation was not handling the continuous selection format viz. SPI chip select would be deasserted even between sequential serial transfers. Use the cs_change variable and correctly set or reset the CONT bit accordingly for case where peripherals require the chip select to be asserted between sequential transfers.

---
 drivers/spi/spi-fsl-dspi.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/spi/spi-fsl-dspi.c +0 -0
index b1ee1f5..41422cd 100644

drivers/spi/spi-fsl-dspi.c static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) · line 268

Quoted 8 lines
drivers/spi/spi-fsl-dspi.c +2 -0
@@ -261,6 +261,8 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
 					SPI_PUSHR_CTAS(0);
+	if (!dspi->cs_change)
+		dspi->dma->tx_dma_buf[i] |= SPI_PUSHR_CONT;
 	dspi->tx += tx_word + 1;
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,

Other transfer mode use:

if ((dspi->cs_change) && (!dspi->len))

        dspi_pushr &= ~SPI_PUSHR_CONT;

which indicates that they only clear SPI_PUSHR_CONT at the very end of a transfer... The DMA code currently deselects after every DMA transfer if dspi->cs_change is set.

Maybe we should use the helper dspi_data_to_pushr to fill the DMA buffer and _clear_ SPI_PUSHR_CONT if necessary like the other transfer modes do... Then we can use the for loop to fill the complete buffer and get rid of some code dupplication.

I see that dspi_data_to_pushr does move len too, which we did not in the DMA case. dspi->len gets incremented only on successful DMA transfer in dspi_dma_xfer. However, I wonder if that is not even a bug: We increment dspi->tx always, but len only on success. This makes len go off sync with regards to the tx pointer which does not help anybody. So lets get rid of the update code in dspi_dma_xfer

--
Stefan

#8 lore raw

Re: [PATCH v2 2/4] spi: spi-fsl-dspi: Fix continuous selection format

Quoted 41 lines · Stefan Agner
Quoted 16 lines · Sanchayan Maity

Current DMA implementation was not handling the continuous selection format viz. SPI chip select would be deasserted even between sequential serial transfers. Use the cs_change variable and correctly set or reset the CONT bit accordingly for case where peripherals require the chip select to be asserted between sequential transfers.

---
 drivers/spi/spi-fsl-dspi.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/spi/spi-fsl-dspi.c +0 -0
index b1ee1f5..41422cd 100644

drivers/spi/spi-fsl-dspi.c static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) · line 268

Quoted 8 lines
drivers/spi/spi-fsl-dspi.c +2 -0
@@ -261,6 +261,8 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
 					SPI_PUSHR_CTAS(0);
+	if (!dspi->cs_change)
+		dspi->dma->tx_dma_buf[i] |= SPI_PUSHR_CONT;
 	dspi->tx += tx_word + 1;
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,

Other transfer mode use:

if ((dspi->cs_change) && (!dspi->len))

        dspi_pushr &= ~SPI_PUSHR_CONT;

which indicates that they only clear SPI_PUSHR_CONT at the very end of a transfer... The DMA code currently deselects after every DMA transfer if dspi->cs_change is set.

Maybe we should use the helper dspi_data_to_pushr to fill the DMA buffer and _clear_ SPI_PUSHR_CONT if necessary like the other transfer modes do... Then we can use the for loop to fill the complete buffer and get rid of some code dupplication.

Quoted 7 lines

I see that dspi_data_to_pushr does move len too, which we did not in the DMA case. dspi->len gets incremented only on successful DMA transfer in dspi_dma_xfer. However, I wonder if that is not even a bug: We increment dspi->tx always, but len only on success. This makes len go off sync with regards to the tx pointer which does not help anybody. So lets get rid of the update code in dspi_dma_xfer

Thanks for the feedback. Using dspi_data_to_pushr really cleans up that tx path very nicely. Why didn't I see it. Will send a follow up patch soon after testing again.

- Sanchayan.

#9 lore raw

PATCH v2 3/4 spi: spi-fsl-dspi: Fix incorrect DMA setup

In reply to Sanchayan Maity

Currently dmaengine_prep_slave_single was being called with length set to the complete DMA buffer size. This resulted in unwanted bytes being transferred to the SPI register leading to clock and MOSI lines having unwanted data even after chip select got deasserted and the required bytes having been transferred.

While at it also clean up the use of curr_xfer_len which is central to the DMA setup, from bytes to DMA transfers for every use.

---
 drivers/spi/spi-fsl-dspi.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)
drivers/spi/spi-fsl-dspi.c +18 -17
index 41422cd..08882f7 100644
@@ -151,6 +151,7 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
 };
 
 struct fsl_dspi_dma {
+	/* Length of transfer in words of DSPI_FIFO_SIZE */
 	u32 curr_xfer_len;
 
 	u32 *tx_dma_buf;
@@ -217,15 +218,13 @@ static void dspi_rx_dma_callback(void *arg)
 	struct fsl_dspi *dspi = arg;
 	struct fsl_dspi_dma *dma = dspi->dma;
 	int rx_word;
-	int i, len;
+	int i;
 	u16 d;
 
 	rx_word = is_double_byte_mode(dspi);
 
-	len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
-		for (i = 0; i < len; i++) {
+		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
 			rx_word ? (*(u16 *)dspi->rx = d) :
 						(*(u8 *)dspi->rx = d);
@@ -242,14 +241,12 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int time_left;
 	int tx_word;
-	int i, len;
+	int i;
 	u16 val;
 
 	tx_word = is_double_byte_mode(dspi);
 
-	len = tx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
-	for (i = 0; i < len - 1; i++) {
+	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
 		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
@@ -267,7 +264,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
 					dma->tx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_MEM_TO_DEV,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_MEM_TO_DEV,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->tx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -283,7 +282,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
 					dma->rx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_DEV_TO_MEM,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->rx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -330,17 +331,17 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int curr_remaining_bytes;
 	int bytes_per_buffer;
-	int tx_word;
+	int word = 1;
 	int ret = 0;
 
-	tx_word = is_double_byte_mode(dspi);
+	if (is_double_byte_mode(dspi))
+		word = 2;
 	curr_remaining_bytes = dspi->len;
+	bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
 	while (curr_remaining_bytes) {
 		/* Check if current transfer fits the DMA buffer */
-		dma->curr_xfer_len = curr_remaining_bytes;
-		bytes_per_buffer = DSPI_DMA_BUFSIZE /
-				(DSPI_FIFO_SIZE / (tx_word ? 2 : 1));
-		if (curr_remaining_bytes > bytes_per_buffer)
+		dma->curr_xfer_len = curr_remaining_bytes / word;
+		if (dma->curr_xfer_len > bytes_per_buffer)
 			dma->curr_xfer_len = bytes_per_buffer;
 
 		ret = dspi_next_xfer_dma_submit(dspi);
@@ -349,7 +350,7 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 			goto exit;
 
 		} else {
-			curr_remaining_bytes -= dma->curr_xfer_len;
+			curr_remaining_bytes -= dma->curr_xfer_len * word;
 			if (curr_remaining_bytes < 0)
 				curr_remaining_bytes = 0;
 			dspi->len = curr_remaining_bytes;
Signature · 1 line
2.10.2
Reviewed-by on v2 3/4
#10 lore raw

Re: [PATCH v2 3/4] spi: spi-fsl-dspi: Fix incorrect DMA setup

Quoted 10 lines · Sanchayan Maity

Currently dmaengine_prep_slave_single was being called with length set to the complete DMA buffer size. This resulted in unwanted bytes being transferred to the SPI register leading to clock and MOSI lines having unwanted data even after chip select got deasserted and the required bytes having been transferred.

While at it also clean up the use of curr_xfer_len which is central to the DMA setup, from bytes to DMA transfers for every use.

Looks good to me:

Quoted 107 lines
---
 drivers/spi/spi-fsl-dspi.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)
drivers/spi/spi-fsl-dspi.c +5 -8
index 41422cd..08882f7 100644
@@ -151,6 +151,7 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
 };
 
 struct fsl_dspi_dma {
+	/* Length of transfer in words of DSPI_FIFO_SIZE */
 	u32 curr_xfer_len;
 
 	u32 *tx_dma_buf;
@@ -217,15 +218,13 @@ static void dspi_rx_dma_callback(void *arg)
 	struct fsl_dspi *dspi = arg;
 	struct fsl_dspi_dma *dma = dspi->dma;
 	int rx_word;
-	int i, len;
+	int i;
 	u16 d;
 
 	rx_word = is_double_byte_mode(dspi);
 
-	len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
-		for (i = 0; i < len; i++) {
+		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
 			rx_word ? (*(u16 *)dspi->rx = d) :
 						(*(u8 *)dspi->rx = d);
@@ -242,14 +241,12 @@ static int dspi_next_xfer_dma_submit(struct
 fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int time_left;
 	int tx_word;
-	int i, len;
+	int i;
 	u16 val;
 
 	tx_word = is_double_byte_mode(dspi);
 
-	len = tx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
-	for (i = 0; i < len - 1; i++) {
+	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
 		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
drivers/spi/spi-fsl-dspi.c +13 -9
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
@@ -267,7 +264,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
 					dma->tx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_MEM_TO_DEV,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_MEM_TO_DEV,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->tx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -283,7 +282,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
 					dma->rx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_DEV_TO_MEM,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->rx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -330,17 +331,17 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int curr_remaining_bytes;
 	int bytes_per_buffer;
-	int tx_word;
+	int word = 1;
 	int ret = 0;
 
-	tx_word = is_double_byte_mode(dspi);
+	if (is_double_byte_mode(dspi))
+		word = 2;
 	curr_remaining_bytes = dspi->len;
+	bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
 	while (curr_remaining_bytes) {
 		/* Check if current transfer fits the DMA buffer */
-		dma->curr_xfer_len = curr_remaining_bytes;
-		bytes_per_buffer = DSPI_DMA_BUFSIZE /
-				(DSPI_FIFO_SIZE / (tx_word ? 2 : 1));
-		if (curr_remaining_bytes > bytes_per_buffer)
+		dma->curr_xfer_len = curr_remaining_bytes / word;
+		if (dma->curr_xfer_len > bytes_per_buffer)
 			dma->curr_xfer_len = bytes_per_buffer;
 
 		ret = dspi_next_xfer_dma_submit(dspi);
@@ -349,7 +350,7 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 			goto exit;
 
 		} else {
-			curr_remaining_bytes -= dma->curr_xfer_len;
+			curr_remaining_bytes -= dma->curr_xfer_len * word;
 			if (curr_remaining_bytes < 0)
 				curr_remaining_bytes = 0;
 			dspi->len = curr_remaining_bytes;
maintainer
#11 lore raw

Applied "spi: spi-fsl-dspi: Fix incorrect DMA setup" to the spi tree

In reply to Sanchayan Maity

The patch

spi: spi-fsl-dspi: Fix incorrect DMA setup

has been applied to the spi tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git

All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying to this mail.

Thanks,
Mark

Quoted 1 line

From 1eaccf210c59e04eb6e9b5469a60d6609c95ac61 Mon Sep 17 00:00:00 2001

From: Sanchayan Maity <[email protected]>
Date: Tue, 22 Nov 2016 12:31:30 +0530
Subject: [PATCH] spi: spi-fsl-dspi: Fix incorrect DMA setup

Currently dmaengine_prep_slave_single was being called with length set to the complete DMA buffer size. This resulted in unwanted bytes being transferred to the SPI register leading to clock and MOSI lines having unwanted data even after chip select got deasserted and the required bytes having been transferred.

While at it also clean up the use of curr_xfer_len which is central to the DMA setup, from bytes to DMA transfers for every use.

---
 drivers/spi/spi-fsl-dspi.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)
drivers/spi/spi-fsl-dspi.c +18 -17
index 22f7ce1279bd..cb41c327bd77 100644
@@ -151,6 +151,7 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
 };
 
 struct fsl_dspi_dma {
+	/* Length of transfer in words of DSPI_FIFO_SIZE */
 	u32 curr_xfer_len;
 
 	u32 *tx_dma_buf;
@@ -217,15 +218,13 @@ static void dspi_rx_dma_callback(void *arg)
 	struct fsl_dspi *dspi = arg;
 	struct fsl_dspi_dma *dma = dspi->dma;
 	int rx_word;
-	int i, len;
+	int i;
 	u16 d;
 
 	rx_word = is_double_byte_mode(dspi);
 
-	len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
-		for (i = 0; i < len; i++) {
+		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
 			rx_word ? (*(u16 *)dspi->rx = d) :
 						(*(u8 *)dspi->rx = d);
@@ -242,14 +241,12 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int time_left;
 	int tx_word;
-	int i, len;
+	int i;
 	u16 val;
 
 	tx_word = is_double_byte_mode(dspi);
 
-	len = tx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
-
-	for (i = 0; i < len - 1; i++) {
+	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
 		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
@@ -265,7 +262,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
 					dma->tx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_MEM_TO_DEV,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_MEM_TO_DEV,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->tx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -281,7 +280,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 	dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
 					dma->rx_dma_phys,
-					DSPI_DMA_BUFSIZE, DMA_DEV_TO_MEM,
+					dma->curr_xfer_len *
+					DMA_SLAVE_BUSWIDTH_4_BYTES,
+					DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 	if (!dma->rx_desc) {
 		dev_err(dev, "Not able to get desc for DMA xfer\n");
@@ -328,17 +329,17 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 	struct device *dev = &dspi->pdev->dev;
 	int curr_remaining_bytes;
 	int bytes_per_buffer;
-	int tx_word;
+	int word = 1;
 	int ret = 0;
 
-	tx_word = is_double_byte_mode(dspi);
+	if (is_double_byte_mode(dspi))
+		word = 2;
 	curr_remaining_bytes = dspi->len;
+	bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
 	while (curr_remaining_bytes) {
 		/* Check if current transfer fits the DMA buffer */
-		dma->curr_xfer_len = curr_remaining_bytes;
-		bytes_per_buffer = DSPI_DMA_BUFSIZE /
-				(DSPI_FIFO_SIZE / (tx_word ? 2 : 1));
-		if (curr_remaining_bytes > bytes_per_buffer)
+		dma->curr_xfer_len = curr_remaining_bytes / word;
+		if (dma->curr_xfer_len > bytes_per_buffer)
 			dma->curr_xfer_len = bytes_per_buffer;
 
 		ret = dspi_next_xfer_dma_submit(dspi);
@@ -347,7 +348,7 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 			goto exit;
 
 		} else {
-			curr_remaining_bytes -= dma->curr_xfer_len;
+			curr_remaining_bytes -= dma->curr_xfer_len * word;
 			if (curr_remaining_bytes < 0)
 				curr_remaining_bytes = 0;
 			dspi->len = curr_remaining_bytes;
Signature · 1 line
2.10.2
#12 lore raw

PATCH v2 4/4 spi: spi-fsl-dspi: Minor code cleanup and error path fixes

In reply to Sanchayan Maity

Code cleanup for improving code readability and error path fixes and cleanup removing use of devm_kfree.

---
 drivers/spi/spi-fsl-dspi.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/spi/spi-fsl-dspi.c +16 -6
index 08882f7..2987a16 100644
@@ -226,8 +226,10 @@ static void dspi_rx_dma_callback(void *arg)
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
 		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
-			rx_word ? (*(u16 *)dspi->rx = d) :
-						(*(u8 *)dspi->rx = d);
+			if (rx_word)
+				*(u16 *)dspi->rx = d;
+			else
+				*(u8 *)dspi->rx = d;
 			dspi->rx += rx_word + 1;
 		}
 	}
@@ -247,14 +249,20 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 	tx_word = is_double_byte_mode(dspi);
 
 	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
-		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+		if (tx_word)
+			val = *(u16 *) dspi->tx;
+		else
+			val = *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
 			SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
 		dspi->tx += tx_word + 1;
 	}
 
-	val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+	if (tx_word)
+		val = *(u16 *) dspi->tx;
+	else
+		val = *(u8 *) dspi->tx;
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
 					SPI_PUSHR_CTAS(0);
@@ -430,9 +438,11 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
 	return 0;
 
 err_slave_config:
-	devm_kfree(dev, dma->rx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->rx_dma_buf, dma->rx_dma_phys);
 err_rx_dma_buf:
-	devm_kfree(dev, dma->tx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->tx_dma_buf, dma->tx_dma_phys);
 err_tx_dma_buf:
 	dma_release_channel(dma->chan_tx);
 err_tx_channel:
Signature · 1 line
2.10.2
#13 lore raw

Re: [PATCH v2 4/4] spi: spi-fsl-dspi: Minor code cleanup and error path fixes

Quoted 2 lines · Sanchayan Maity

Code cleanup for improving code readability and error path fixes and cleanup removing use of devm_kfree.

Two things in one, not very nice. Especially the dma_free_coherent is really a bug and the other is a cleanup. Can you make a separate patch for the bug?

As for the cleanup, I don't like the one line conditions too, but I don't think it is worth a patch. At least the TX path should be solved with my suggestion in patch 2.

--
Stefan

Quoted 62 lines
---
 drivers/spi/spi-fsl-dspi.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/spi/spi-fsl-dspi.c +12 -4
index 08882f7..2987a16 100644
@@ -226,8 +226,10 @@ static void dspi_rx_dma_callback(void *arg)
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
 		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
-			rx_word ? (*(u16 *)dspi->rx = d) :
-						(*(u8 *)dspi->rx = d);
+			if (rx_word)
+				*(u16 *)dspi->rx = d;
+			else
+				*(u8 *)dspi->rx = d;
 			dspi->rx += rx_word + 1;
 		}
 	}
@@ -247,14 +249,20 @@ static int dspi_next_xfer_dma_submit(struct
 fsl_dspi *dspi)
 	tx_word = is_double_byte_mode(dspi);
 
 	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
-		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+		if (tx_word)
+			val = *(u16 *) dspi->tx;
+		else
+			val = *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
 			SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
 		dspi->tx += tx_word + 1;
 	}
 
-	val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+	if (tx_word)
+		val = *(u16 *) dspi->tx;
+	else
+		val = *(u8 *) dspi->tx;
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
drivers/spi/spi-fsl-dspi.c +4 -2
 					SPI_PUSHR_CTAS(0);
@@ -430,9 +438,11 @@ static int dspi_request_dma(struct fsl_dspi
 *dspi, phys_addr_t phy_addr)
 	return 0;
 
 err_slave_config:
-	devm_kfree(dev, dma->rx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->rx_dma_buf, dma->rx_dma_phys);
 err_rx_dma_buf:
-	devm_kfree(dev, dma->tx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->tx_dma_buf, dma->tx_dma_phys);
 err_tx_dma_buf:
 	dma_release_channel(dma->chan_tx);

err_tx_channel:

#14 lore raw

Re: [PATCH v2 4/4] spi: spi-fsl-dspi: Minor code cleanup and error path fixes

Quoted 11 lines · Stefan Agner
Quoted 2 lines · Sanchayan Maity

Code cleanup for improving code readability and error path fixes and cleanup removing use of devm_kfree.

Two things in one, not very nice. Especially the dma_free_coherent is really a bug and the other is a cleanup. Can you make a separate patch for the bug?

As for the cleanup, I don't like the one line conditions too, but I don't think it is worth a patch. At least the TX path should be solved with my suggestion in patch 2.

Agreed.

- Sanchayan.

Quoted 66 lines

--
Stefan

Quoted 62 lines
---
 drivers/spi/spi-fsl-dspi.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/spi/spi-fsl-dspi.c +12 -4
index 08882f7..2987a16 100644
@@ -226,8 +226,10 @@ static void dspi_rx_dma_callback(void *arg)
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
 		for (i = 0; i < dma->curr_xfer_len; i++) {
 			d = dspi->dma->rx_dma_buf[i];
-			rx_word ? (*(u16 *)dspi->rx = d) :
-						(*(u8 *)dspi->rx = d);
+			if (rx_word)
+				*(u16 *)dspi->rx = d;
+			else
+				*(u8 *)dspi->rx = d;
 			dspi->rx += rx_word + 1;
 		}
 	}
@@ -247,14 +249,20 @@ static int dspi_next_xfer_dma_submit(struct
 fsl_dspi *dspi)
 	tx_word = is_double_byte_mode(dspi);
 
 	for (i = 0; i < dma->curr_xfer_len - 1; i++) {
-		val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+		if (tx_word)
+			val = *(u16 *) dspi->tx;
+		else
+			val = *(u8 *) dspi->tx;
 		dspi->dma->tx_dma_buf[i] =
 			SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
 			SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
 		dspi->tx += tx_word + 1;
 	}
 
-	val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+	if (tx_word)
+		val = *(u16 *) dspi->tx;
+	else
+		val = *(u8 *) dspi->tx;
 	dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
 					SPI_PUSHR_PCS(dspi->cs) |
drivers/spi/spi-fsl-dspi.c +4 -2
 					SPI_PUSHR_CTAS(0);
@@ -430,9 +438,11 @@ static int dspi_request_dma(struct fsl_dspi
 *dspi, phys_addr_t phy_addr)
 	return 0;
 
 err_slave_config:
-	devm_kfree(dev, dma->rx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->rx_dma_buf, dma->rx_dma_phys);
 err_rx_dma_buf:
-	devm_kfree(dev, dma->tx_dma_buf);
+	dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+			dma->tx_dma_buf, dma->tx_dma_phys);
 err_tx_dma_buf:
 	dma_release_channel(dma->chan_tx);

err_tx_channel: