2021-04-08 04:05:25

by quanyang wang

[permalink] [raw]
Subject: [PATCH 0/4] spi: spi-zynqmp-gpspi: fix some issues

From: Quanyang Wang <[email protected]>

Hello,

This series fix some issues that occurs when the gqspi driver switches to spi-mem framework.

Hi Amit,
I rewrite the "Subject" and "commit message" of these patches, so they
look different from the ones which you reviewed before. I still keep
your "Reviewed-by" and hope you will not mind.

Regards,
Quanyang Wang

Quanyang Wang (4):
spi: spi-zynqmp-gqspi: use wait_for_completion_timeout to make
zynqmp_qspi_exec_op not interruptible
spi: spi-zynqmp-gqspi: add mutex locking for exec_op
spi: spi-zynqmp-gqspi: transmit dummy circles by using the
controller's internal functionality
spi: spi-zynqmp-gqspi: fix incorrect operating mode in
zynqmp_qspi_read_op

drivers/spi/spi-zynqmp-gqspi.c | 53 +++++++++++++++++-----------------
1 file changed, 27 insertions(+), 26 deletions(-)

--
2.25.1


2021-04-08 04:05:32

by quanyang wang

[permalink] [raw]
Subject: [PATCH 1/4] spi: spi-zynqmp-gqspi: use wait_for_completion_timeout to make zynqmp_qspi_exec_op not interruptible

From: Quanyang Wang <[email protected]>

When Ctrl+C occurs during the process of zynqmp_qspi_exec_op, the function
wait_for_completion_interruptible_timeout will return a non-zero value
-ERESTARTSYS immediately. This will disrupt the SPI memory operation
because the data transmitting may begin before the command or address
transmitting completes. Use wait_for_completion_timeout to prevent
the process from being interruptible.

This patch fixes the error as below:
root@xilinx-zynqmp:~# flash_erase /dev/mtd3 0 0
Erasing 4 Kibyte @ 3d000 -- 4 % complete
(Press Ctrl+C)
[ 169.581911] zynqmp-qspi ff0f0000.spi: Chip select timed out
[ 170.585907] zynqmp-qspi ff0f0000.spi: Chip select timed out
[ 171.589910] zynqmp-qspi ff0f0000.spi: Chip select timed out
[ 172.593910] zynqmp-qspi ff0f0000.spi: Chip select timed out
[ 173.597907] zynqmp-qspi ff0f0000.spi: Chip select timed out
[ 173.603480] spi-nor spi0.0: Erase operation failed.
[ 173.608368] spi-nor spi0.0: Attempted to modify a protected sector.

Fixes: 1c26372e5aa9 ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: Quanyang Wang <[email protected]>
Reviewed-by: Amit Kumar Mahapatra <[email protected]>
---
drivers/spi/spi-zynqmp-gqspi.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index c8fa6ee18ae7..d49ab6575553 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -973,7 +973,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
GQSPI_IER_GENFIFOEMPTY_MASK |
GQSPI_IER_TXNOT_FULL_MASK);
- if (!wait_for_completion_interruptible_timeout
+ if (!wait_for_completion_timeout
(&xqspi->data_completion, msecs_to_jiffies(1000))) {
err = -ETIMEDOUT;
kfree(tmpbuf);
@@ -1001,7 +1001,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
GQSPI_IER_TXEMPTY_MASK |
GQSPI_IER_GENFIFOEMPTY_MASK |
GQSPI_IER_TXNOT_FULL_MASK);
- if (!wait_for_completion_interruptible_timeout
+ if (!wait_for_completion_timeout
(&xqspi->data_completion, msecs_to_jiffies(1000))) {
err = -ETIMEDOUT;
goto return_err;
@@ -1076,7 +1076,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
GQSPI_IER_RXEMPTY_MASK);
}
}
- if (!wait_for_completion_interruptible_timeout
+ if (!wait_for_completion_timeout
(&xqspi->data_completion, msecs_to_jiffies(1000)))
err = -ETIMEDOUT;
}
--
2.25.1

2021-04-08 04:05:34

by quanyang wang

[permalink] [raw]
Subject: [PATCH 2/4] spi: spi-zynqmp-gqspi: add mutex locking for exec_op

From: Quanyang Wang <[email protected]>

The spi-mem framework has no locking to prevent ctlr->mem_ops->exec_op
from concurrency. So add the locking to zynqmp_qspi_exec_op.

Fixes: 1c26372e5aa9 ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: Quanyang Wang <[email protected]>
Reviewed-by: Amit Kumar Mahapatra <[email protected]>
---
drivers/spi/spi-zynqmp-gqspi.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index d49ab6575553..3b39461d58b3 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -173,6 +173,7 @@ struct zynqmp_qspi {
u32 genfifoentry;
enum mode_type mode;
struct completion data_completion;
+ struct mutex op_lock;
};

/**
@@ -951,6 +952,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth);

+ mutex_lock(&xqspi->op_lock);
zynqmp_qspi_config_op(xqspi, mem->spi);
zynqmp_qspi_chipselect(mem->spi, false);
genfifoentry |= xqspi->genfifocs;
@@ -1084,6 +1086,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
return_err:

zynqmp_qspi_chipselect(mem->spi, true);
+ mutex_unlock(&xqspi->op_lock);

return err;
}
@@ -1156,6 +1159,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_pclk;
}

+ mutex_init(&xqspi->op_lock);
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
--
2.25.1

2021-04-08 04:06:13

by quanyang wang

[permalink] [raw]
Subject: [PATCH 4/4] spi: spi-zynqmp-gqspi: fix incorrect operating mode in zynqmp_qspi_read_op

From: Quanyang Wang <[email protected]>

When starting a read operation, we should call zynqmp_qspi_setuprxdma
first to set xqspi->mode according to xqspi->bytes_to_receive and
to calculate correct xqspi->dma_rx_bytes. Then in the function
zynqmp_qspi_fillgenfifo, generate the appropriate command with
operating mode and bytes to transfer, and fill the GENFIFO with
the command to perform the read operation.

Calling zynqmp_qspi_fillgenfifo before zynqmp_qspi_setuprxdma will
result in incorrect transfer length and operating mode. So change
the calling order to fix this issue.

Fixes: 1c26372e5aa9 ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: Quanyang Wang <[email protected]>
Reviewed-by: Amit Kumar Mahapatra <[email protected]>
---
drivers/spi/spi-zynqmp-gqspi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index cf73a069b759..036d8ae41c06 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -827,8 +827,8 @@ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits,
static void zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits,
u32 genfifoentry)
{
- zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry);
zynqmp_qspi_setuprxdma(xqspi);
+ zynqmp_qspi_fillgenfifo(xqspi, rx_nbits, genfifoentry);
}

/**
--
2.25.1

2021-04-08 04:07:53

by quanyang wang

[permalink] [raw]
Subject: [PATCH 3/4] spi: spi-zynqmp-gqspi: transmit dummy circles by using the controller's internal functionality

From: Quanyang Wang <[email protected]>

There is a data corruption issue that occurs in the reading operation
(cmd:0x6c) when transmitting common data as dummy circles.

The gqspi controller has the functionality to send dummy clock circles.
When writing data with the fields [receive, transmit, data_xfer] = [0,0,1]
to the Generic FIFO, and configuring the correct SPI mode, the controller
will transmit dummy circles.

So let's switch to hardware dummy cycles transfer to fix this issue.

Fixes: 1c26372e5aa9 ("spi: spi-zynqmp-gqspi: Update driver to use spi-mem framework")
Signed-off-by: Quanyang Wang <[email protected]>
Reviewed-by: Amit Kumar Mahapatra <[email protected]>
---
drivers/spi/spi-zynqmp-gqspi.c | 40 +++++++++++++++-------------------
1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index 3b39461d58b3..cf73a069b759 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -521,7 +521,7 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size)
{
u32 count = 0, intermediate;

- while ((xqspi->bytes_to_transfer > 0) && (count < size)) {
+ while ((xqspi->bytes_to_transfer > 0) && (count < size) && (xqspi->txbuf)) {
memcpy(&intermediate, xqspi->txbuf, 4);
zynqmp_gqspi_write(xqspi, GQSPI_TXD_OFST, intermediate);

@@ -580,7 +580,7 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
genfifoentry |= GQSPI_GENFIFO_TX;
transfer_len = xqspi->bytes_to_transfer;
- } else {
+ } else if (xqspi->rxbuf) {
genfifoentry &= ~GQSPI_GENFIFO_TX;
genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
genfifoentry |= GQSPI_GENFIFO_RX;
@@ -588,6 +588,11 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
transfer_len = xqspi->dma_rx_bytes;
else
transfer_len = xqspi->bytes_to_receive;
+ } else {
+ /* Sending dummy circles here */
+ genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX);
+ genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
+ transfer_len = xqspi->bytes_to_transfer;
}
genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits);
xqspi->genfifoentry = genfifoentry;
@@ -1011,32 +1016,23 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
}

if (op->dummy.nbytes) {
- tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL | GFP_DMA);
- if (!tmpbuf)
- return -ENOMEM;
- memset(tmpbuf, 0xff, op->dummy.nbytes);
- reinit_completion(&xqspi->data_completion);
- xqspi->txbuf = tmpbuf;
+ xqspi->txbuf = NULL;
xqspi->rxbuf = NULL;
- xqspi->bytes_to_transfer = op->dummy.nbytes;
+ /*
+ * xqspi->bytes_to_transfer here represents the dummy circles
+ * which need to be sent.
+ */
+ xqspi->bytes_to_transfer = op->dummy.nbytes * 8 / op->dummy.buswidth;
xqspi->bytes_to_receive = 0;
- zynqmp_qspi_write_op(xqspi, op->dummy.buswidth,
+ /*
+ * Using op->data.buswidth instead of op->dummy.buswidth here because
+ * we need to use it to configure the correct SPI mode.
+ */
+ zynqmp_qspi_write_op(xqspi, op->data.buswidth,
genfifoentry);
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
GQSPI_CFG_START_GEN_FIFO_MASK);
- zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
- GQSPI_IER_TXEMPTY_MASK |
- GQSPI_IER_GENFIFOEMPTY_MASK |
- GQSPI_IER_TXNOT_FULL_MASK);
- if (!wait_for_completion_interruptible_timeout
- (&xqspi->data_completion, msecs_to_jiffies(1000))) {
- err = -ETIMEDOUT;
- kfree(tmpbuf);
- goto return_err;
- }
-
- kfree(tmpbuf);
}

if (op->data.nbytes) {
--
2.25.1

2021-04-09 16:25:02

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 0/4] spi: spi-zynqmp-gpspi: fix some issues

On Thu, 8 Apr 2021 12:02:19 +0800, [email protected] wrote:
> This series fix some issues that occurs when the gqspi driver switches to spi-mem framework.
>
> Hi Amit,
> I rewrite the "Subject" and "commit message" of these patches, so they
> look different from the ones which you reviewed before. I still keep
> your "Reviewed-by" and hope you will not mind.
>
> [...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/4] spi: spi-zynqmp-gqspi: use wait_for_completion_timeout to make zynqmp_qspi_exec_op not interruptible
commit: a16bff68b75fd082d36aa0b14b540bd7a3ebebbd
[2/4] spi: spi-zynqmp-gqspi: add mutex locking for exec_op
commit: a0f65be6e880a14d3445b75e7dc03d7d015fc922
[3/4] spi: spi-zynqmp-gqspi: transmit dummy circles by using the controller's internal functionality
commit: 8ad07d79bd56a531990a1a3f3f1c0eb19d2de806
[4/4] spi: spi-zynqmp-gqspi: fix incorrect operating mode in zynqmp_qspi_read_op
commit: 41d310930084502433fcb3c4baf219e7424b7734

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