diff mbox series

[v2] mtd: rawnand: cadence: support 64-bit slave dma interface

Message ID 20221017152640.32362-1-vkorenblit@sequans.com
State Changes Requested
Headers show
Series [v2] mtd: rawnand: cadence: support 64-bit slave dma interface | expand

Commit Message

Valentin Korenblit Oct. 17, 2022, 3:26 p.m. UTC
32-bit accesses on 64-bit sdma trigger sdma_err in intr_status register.

Check dma capabilities before reading/writing from/to sdma interface.

Link to discussion:
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org/thread/3NMACGIM5NDUBPXRT5RTBZON6LQE5A3B/

Signed-off-by: Valentin Korenblit <vkorenblit@sequans.com>

---

Changes v1 -> v2:
	- Replaced ioread64_rep by cadence_nand_readsq (suggested by Arnd)
	- Replaced iowrite64_rep by cadence_nand_writesq (suggested by Arnd)
	- Do not try to access 64-bit sdma if __raw_readq/__raw_writeq are not defined
---
 .../mtd/nand/raw/cadence-nand-controller.c    | 96 ++++++++++++++++---
 1 file changed, 84 insertions(+), 12 deletions(-)

Comments

Arnd Bergmann Oct. 17, 2022, 6:56 p.m. UTC | #1
On Mon, Oct 17, 2022, at 5:26 PM, Valentin Korenblit wrote:
> 32-bit accesses on 64-bit sdma trigger sdma_err in intr_status register.
>
> Check dma capabilities before reading/writing from/to sdma interface.
>
> Link to discussion:
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org/thread/3NMACGIM5NDUBPXRT5RTBZON6LQE5A3B/
>
> Signed-off-by: Valentin Korenblit <vkorenblit@sequans.com>

Seems reasonable overall based on the discussion so far.

Minor comments:

> Changes v1 -> v2:
> 	- Replaced ioread64_rep by cadence_nand_readsq (suggested by Arnd)
> 	- Replaced iowrite64_rep by cadence_nand_writesq (suggested by Arnd)
> 	- Do not try to access 64-bit sdma if __raw_readq/__raw_writeq are not defined


> +static inline void cadence_nand_readsq(struct cdns_nand_ctrl 
> *cdns_ctrl,
> +				       void *buffer, unsigned int count)
> +{
> +#ifdef __raw_readq
> +	const volatile void __iomem *addr = cdns_ctrl->io.virt;
> +
> +        if (count) {
> +                u64 *buf = buffer;
> +
> +                do {
> +                        u64 x = __raw_readq(addr);
> +                        *buf++ = x;
> +                } while (--count);
> +        }

While this is correct, I suppose you don't actually need that
loop any more, since architectures that have __raw_readq()
should also also have ioread64_rep() or readsq(). We actually
just had a few issues with that in another context, but I think
starting with 6.1-rc1 you should be able to rely on that ;-)

> +#else
> +	dev_err(cdns_ctrl->dev,
> +		"cannot read 64-bit sdma on !64-bit architectures");
> +#endif

It would be nice to print an error at probe time and fail attaching
the device rather than waiting for the first transfer to continue
with incorrect data.

      Arnd
diff mbox series

Patch

diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 9dac3ca69d57..0309a6b0d3d3 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -1869,6 +1869,46 @@  static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,
 	return -EIO;
 }
 
+static inline void cadence_nand_readsq(struct cdns_nand_ctrl *cdns_ctrl,
+				       void *buffer, unsigned int count)
+{
+#ifdef __raw_readq
+	const volatile void __iomem *addr = cdns_ctrl->io.virt;
+
+        if (count) {
+                u64 *buf = buffer;
+
+                do {
+                        u64 x = __raw_readq(addr);
+                        *buf++ = x;
+                } while (--count);
+        }
+#else
+	dev_err(cdns_ctrl->dev,
+		"cannot read 64-bit sdma on !64-bit architectures");
+#endif
+}
+
+static inline void cadence_nand_writesq(struct cdns_nand_ctrl *cdns_ctrl,
+					const void *buffer,
+					unsigned int count)
+{
+#ifdef __raw_writeq
+	volatile void __iomem *addr = cdns_ctrl->io.virt;
+
+        if (count) {
+                const u64 *buf = buffer;
+
+                do {
+                        __raw_writeq(*buf++, addr);
+                } while (--count);
+        }
+#else
+	dev_err(cdns_ctrl->dev,
+		"cannot write 64-bit sdma on !64-bit architectures");
+#endif
+}
+
 static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl,
 				 u8 *buf, int len)
 {
@@ -1882,17 +1922,33 @@  static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl,
 		return status;
 
 	if (!cdns_ctrl->caps1->has_dma) {
-		int len_in_words = len >> 2;
+		u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
+
+		int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
 
 		/* read alingment data */
-		ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+		if (data_dma_width == 4)
+			ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+		else
+			cadence_nand_readsq(cdns_ctrl, buf, len_in_words);
+
 		if (sdma_size > len) {
+			int read_bytes = (data_dma_width == 4) ?
+				len_in_words << 2 : len_in_words << 3;
+
 			/* read rest data from slave DMA interface if any */
-			ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
-				     sdma_size / 4 - len_in_words);
+			if (data_dma_width == 4)
+				ioread32_rep(cdns_ctrl->io.virt,
+					     cdns_ctrl->buf,
+					     sdma_size / 4 - len_in_words);
+			else
+				cadence_nand_readsq(cdns_ctrl,
+					     cdns_ctrl->buf,
+					     sdma_size / 8 - len_in_words);
+
 			/* copy rest of data */
-			memcpy(buf + (len_in_words << 2), cdns_ctrl->buf,
-			       len - (len_in_words << 2));
+			memcpy(buf + read_bytes, cdns_ctrl->buf,
+			       len - read_bytes);
 		}
 		return 0;
 	}
@@ -1936,16 +1992,32 @@  static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl,
 		return status;
 
 	if (!cdns_ctrl->caps1->has_dma) {
-		int len_in_words = len >> 2;
+		u8 data_dma_width = cdns_ctrl->caps2.data_dma_width;
+
+		int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3;
+
+		if (data_dma_width == 4)
+			iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
+		else
+			cadence_nand_writesq(cdns_ctrl, buf, len_in_words);
 
-		iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words);
 		if (sdma_size > len) {
+			int written_bytes = (data_dma_width == 4) ?
+				len_in_words << 2 : len_in_words << 3;
+
 			/* copy rest of data */
-			memcpy(cdns_ctrl->buf, buf + (len_in_words << 2),
-			       len - (len_in_words << 2));
+			memcpy(cdns_ctrl->buf, buf + written_bytes,
+			       len - written_bytes);
+
 			/* write all expected by nand controller data */
-			iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf,
-				      sdma_size / 4 - len_in_words);
+			if (data_dma_width == 4)
+				iowrite32_rep(cdns_ctrl->io.virt,
+					      cdns_ctrl->buf,
+					      sdma_size / 4 - len_in_words);
+			else
+				cadence_nand_writesq(cdns_ctrl,
+					      cdns_ctrl->buf,
+					      sdma_size / 8 - len_in_words);
 		}
 
 		return 0;