All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/13] Pipelined ECC engines & Macronix support
@ 2021-12-14 11:41 ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Hello all,

This is a second version of the second half of the "External ECC engines
& Macronix support" series, focusing on the pipelined support.

Cheers,
Miquèl

Changes in v5:
* Moved a helper in the core as it seems that it will be useful for
  other ECC engines as well (Xiangsheng Hou for Mediatek will need it).
* Changed the parameters of the spi_mem_generic_supports_op() function
  in order to take a structure as input instead of a list of arguments,
  which will be much easier to complement in the future if ever needed.

Changes in v4:
* The first half of the series has been left aside (all the binding
  changes + the external mode in the Macronix driver), now let's focus
  on the pipelined mode.
* Added the ecc_en spi_mem_op structure parameter in a dedicated commit.
* Introduced a new helper for supporting generically the supported ops.
* Used this new helper in the macronix driver.
* By default all the other drivers would refuse a spi_mem_op with ecc_en
  enabled.

Changes in v3:
* Added Mark's R-by.
* Added a commit changing the initialization order between the dirmaps
  and the ECC engine so that the core might now if we are using a
  pipelined engine or not.
* Stopped creating additional dirmaps with ECC if the engine is not a
  pipelined engine.
* Solved the kernel test robot reports. In particular, I added a
  dependency on MTD_NAND_ECC to Macronix SPI controller driver.
* Added a patch to clean the NAND controller yaml file before moving
  some bits to nand-chip.yaml. This addresses the comments made by Rob
  about the useless allOf's.
* Used platform_get_irq_byname_optional() in order to avoid useless
  warnings when there is no IRQ.

Changes in v2:
* Fixed the bindings and added Rob's acks when relevant.
* Added locking in the ECC engine driver.
* Brought more changes in the core in order to bring the ECC information
  into the spi_mem_op structure with the idea of avoiding any races
  between parallel calls on the same engine.
* Reorganized the ECC driver entirely in order to have a per-engine mxic
  structure plus a per-NAND context. This lead to a number of changes
  internally which cannot all be listed.

Changes since the RFC:
* Rebased on top of v5.15-rc1.
* Fixed the dirmap configuration.
* Added the various tags received.
* Fixed the bindings as reported by the robots.
* Fixed the return value of the helper counting bitflips.
* Included a fix from Jaime Liao in the external pattern logic.
* Added the yaml conversion of Macronix SPI controller description.
* Added the yaml conversion of the SPI-NAND description.
* Created a nand-chip.yaml file to share properties between SPI-NAND and
  raw NAND.

Miquel Raynal (13):
  mtd: nand: ecc: Provide a helper to retrieve a pilelined engine device
  mtd: nand: mxic-ecc: Support SPI pipelined mode
  mtd: spinand: Delay a little bit the dirmap creation
  spi: spi-mem: Create a helper to gather all the supports_op checks
  spi: spi-mem: Export the spi_mem_generic_supports_op() helper
  spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
  mtd: spinand: Create direct mapping descriptors for ECC operations
  spi: mxic: Fix the transmit path
  spi: mxic: Create a helper to configure the controller before an
    operation
  spi: mxic: Create a helper to ease the start of an operation
  spi: mxic: Add support for direct mapping
  spi: mxic: Use spi_mem_generic_supports_op()
  spi: mxic: Add support for pipelined ECC operations

 drivers/mtd/nand/ecc-mxic.c       | 181 +++++++++++++++-
 drivers/mtd/nand/ecc.c            |  31 +++
 drivers/mtd/nand/spi/core.c       |  51 ++++-
 drivers/spi/Kconfig               |   2 +-
 drivers/spi/spi-mem.c             |  40 +++-
 drivers/spi/spi-mxic.c            | 337 ++++++++++++++++++++++++------
 include/linux/mtd/nand-ecc-mxic.h |  49 +++++
 include/linux/mtd/nand.h          |   1 +
 include/linux/mtd/spinand.h       |   2 +
 include/linux/spi/spi-mem.h       |  25 +++
 10 files changed, 639 insertions(+), 80 deletions(-)
 create mode 100644 include/linux/mtd/nand-ecc-mxic.h

-- 
2.27.0


^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v5 00/13] Pipelined ECC engines & Macronix support
@ 2021-12-14 11:41 ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Hello all,

This is a second version of the second half of the "External ECC engines
& Macronix support" series, focusing on the pipelined support.

Cheers,
Miquèl

Changes in v5:
* Moved a helper in the core as it seems that it will be useful for
  other ECC engines as well (Xiangsheng Hou for Mediatek will need it).
* Changed the parameters of the spi_mem_generic_supports_op() function
  in order to take a structure as input instead of a list of arguments,
  which will be much easier to complement in the future if ever needed.

Changes in v4:
* The first half of the series has been left aside (all the binding
  changes + the external mode in the Macronix driver), now let's focus
  on the pipelined mode.
* Added the ecc_en spi_mem_op structure parameter in a dedicated commit.
* Introduced a new helper for supporting generically the supported ops.
* Used this new helper in the macronix driver.
* By default all the other drivers would refuse a spi_mem_op with ecc_en
  enabled.

Changes in v3:
* Added Mark's R-by.
* Added a commit changing the initialization order between the dirmaps
  and the ECC engine so that the core might now if we are using a
  pipelined engine or not.
* Stopped creating additional dirmaps with ECC if the engine is not a
  pipelined engine.
* Solved the kernel test robot reports. In particular, I added a
  dependency on MTD_NAND_ECC to Macronix SPI controller driver.
* Added a patch to clean the NAND controller yaml file before moving
  some bits to nand-chip.yaml. This addresses the comments made by Rob
  about the useless allOf's.
* Used platform_get_irq_byname_optional() in order to avoid useless
  warnings when there is no IRQ.

Changes in v2:
* Fixed the bindings and added Rob's acks when relevant.
* Added locking in the ECC engine driver.
* Brought more changes in the core in order to bring the ECC information
  into the spi_mem_op structure with the idea of avoiding any races
  between parallel calls on the same engine.
* Reorganized the ECC driver entirely in order to have a per-engine mxic
  structure plus a per-NAND context. This lead to a number of changes
  internally which cannot all be listed.

Changes since the RFC:
* Rebased on top of v5.15-rc1.
* Fixed the dirmap configuration.
* Added the various tags received.
* Fixed the bindings as reported by the robots.
* Fixed the return value of the helper counting bitflips.
* Included a fix from Jaime Liao in the external pattern logic.
* Added the yaml conversion of Macronix SPI controller description.
* Added the yaml conversion of the SPI-NAND description.
* Created a nand-chip.yaml file to share properties between SPI-NAND and
  raw NAND.

Miquel Raynal (13):
  mtd: nand: ecc: Provide a helper to retrieve a pilelined engine device
  mtd: nand: mxic-ecc: Support SPI pipelined mode
  mtd: spinand: Delay a little bit the dirmap creation
  spi: spi-mem: Create a helper to gather all the supports_op checks
  spi: spi-mem: Export the spi_mem_generic_supports_op() helper
  spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
  mtd: spinand: Create direct mapping descriptors for ECC operations
  spi: mxic: Fix the transmit path
  spi: mxic: Create a helper to configure the controller before an
    operation
  spi: mxic: Create a helper to ease the start of an operation
  spi: mxic: Add support for direct mapping
  spi: mxic: Use spi_mem_generic_supports_op()
  spi: mxic: Add support for pipelined ECC operations

 drivers/mtd/nand/ecc-mxic.c       | 181 +++++++++++++++-
 drivers/mtd/nand/ecc.c            |  31 +++
 drivers/mtd/nand/spi/core.c       |  51 ++++-
 drivers/spi/Kconfig               |   2 +-
 drivers/spi/spi-mem.c             |  40 +++-
 drivers/spi/spi-mxic.c            | 337 ++++++++++++++++++++++++------
 include/linux/mtd/nand-ecc-mxic.h |  49 +++++
 include/linux/mtd/nand.h          |   1 +
 include/linux/mtd/spinand.h       |   2 +
 include/linux/spi/spi-mem.h       |  25 +++
 10 files changed, 639 insertions(+), 80 deletions(-)
 create mode 100644 include/linux/mtd/nand-ecc-mxic.h

-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v5 01/13] mtd: nand: ecc: Provide a helper to retrieve a pilelined engine device
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

In a pipelined engine situation, we might either have the host which
internally has support for error correction, or have it using an
external hardware block for this purpose. In the former case, the host
is also the ECC engine. In the latter case, it is not. In order to get
the right pointers on the right devices (for example: in order to devm_*
allocate variables), let's introduce this helper which can safely be
called by pipelined ECC engines in order to retrieve the right device
structure.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc.c   | 31 +++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
index 078f5ec38de3..5250764cedee 100644
--- a/drivers/mtd/nand/ecc.c
+++ b/drivers/mtd/nand/ecc.c
@@ -699,6 +699,37 @@ void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
 }
 EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
 
+/*
+ * In the case of a pipelined engine, the device registering the ECC
+ * engine is not necessarily the ECC engine itself but may be a host controller.
+ * It is then useful to provide a helper to retrieve the right device object
+ * which actually represents the ECC engine.
+ */
+struct device *nand_ecc_get_engine_dev(struct device *host)
+{
+	struct platform_device *ecc_pdev;
+	struct device_node *np;
+
+	/*
+	 * If the device node contains this property, it means we need to follow
+	 * it in order to get the right ECC engine device we are looking for.
+	 */
+	np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0);
+	if (!np)
+		return host;
+
+	ecc_pdev = of_find_device_by_node(np);
+	if (!ecc_pdev) {
+		of_node_put(np);
+		return NULL;
+	}
+
+	platform_device_put(ecc_pdev);
+	of_node_put(np);
+
+	return &ecc_pdev->dev;
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
 MODULE_DESCRIPTION("Generic ECC engine");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b617efa0a881..615b3e3a3920 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -309,6 +309,7 @@ struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand);
 struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand);
 struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand);
 void nand_ecc_put_on_host_hw_engine(struct nand_device *nand);
+struct device *nand_ecc_get_engine_dev(struct device *host);
 
 #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
 struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 01/13] mtd: nand: ecc: Provide a helper to retrieve a pilelined engine device
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

In a pipelined engine situation, we might either have the host which
internally has support for error correction, or have it using an
external hardware block for this purpose. In the former case, the host
is also the ECC engine. In the latter case, it is not. In order to get
the right pointers on the right devices (for example: in order to devm_*
allocate variables), let's introduce this helper which can safely be
called by pipelined ECC engines in order to retrieve the right device
structure.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc.c   | 31 +++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
index 078f5ec38de3..5250764cedee 100644
--- a/drivers/mtd/nand/ecc.c
+++ b/drivers/mtd/nand/ecc.c
@@ -699,6 +699,37 @@ void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
 }
 EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
 
+/*
+ * In the case of a pipelined engine, the device registering the ECC
+ * engine is not necessarily the ECC engine itself but may be a host controller.
+ * It is then useful to provide a helper to retrieve the right device object
+ * which actually represents the ECC engine.
+ */
+struct device *nand_ecc_get_engine_dev(struct device *host)
+{
+	struct platform_device *ecc_pdev;
+	struct device_node *np;
+
+	/*
+	 * If the device node contains this property, it means we need to follow
+	 * it in order to get the right ECC engine device we are looking for.
+	 */
+	np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0);
+	if (!np)
+		return host;
+
+	ecc_pdev = of_find_device_by_node(np);
+	if (!ecc_pdev) {
+		of_node_put(np);
+		return NULL;
+	}
+
+	platform_device_put(ecc_pdev);
+	of_node_put(np);
+
+	return &ecc_pdev->dev;
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
 MODULE_DESCRIPTION("Generic ECC engine");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b617efa0a881..615b3e3a3920 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -309,6 +309,7 @@ struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand);
 struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand);
 struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand);
 void nand_ecc_put_on_host_hw_engine(struct nand_device *nand);
+struct device *nand_ecc_get_engine_dev(struct device *host);
 
 #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
 struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void);
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 02/13] mtd: nand: mxic-ecc: Support SPI pipelined mode
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Introduce the support for another possible configuration: the ECC
engine may work as DMA master (pipelined) and move itself the data
to/from the NAND chip into the buffer, applying the necessary
corrections/computations on the fly.

This driver offers an ECC engine implementation that must be
instatiated from a SPI controller driver.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc-mxic.c       | 181 +++++++++++++++++++++++++++++-
 include/linux/mtd/nand-ecc-mxic.h |  49 ++++++++
 2 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/mtd/nand-ecc-mxic.h

diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c
index ea88a411ed70..3d2d20a6d465 100644
--- a/drivers/mtd/nand/ecc-mxic.c
+++ b/drivers/mtd/nand/ecc-mxic.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand-ecc-mxic.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
@@ -40,7 +41,9 @@
 #define INTRPT_SIG_EN 0x0C
 /* Host Controller Configuration */
 #define HC_CONFIG 0x10
+#define   DEV2MEM 0 /* TRANS_TYP_DMA in the spec */
 #define   MEM2MEM BIT(4) /* TRANS_TYP_IO in the spec */
+#define   MAPPING BIT(5) /* TRANS_TYP_MAPPING in the spec */
 #define   ECC_PACKED 0 /* LAYOUT_TYP_INTEGRATED in the spec */
 #define   ECC_INTERLEAVED BIT(2) /* LAYOUT_TYP_DISTRIBUTED in the spec */
 #define   BURST_TYP_FIXED 0
@@ -87,6 +90,7 @@ struct mxic_ecc_engine {
 	int irq;
 	struct completion complete;
 	struct nand_ecc_engine external_engine;
+	struct nand_ecc_engine pipelined_engine;
 	struct mutex lock;
 };
 
@@ -104,6 +108,7 @@ struct mxic_ecc_ctx {
 	u8 *oobwithstat;
 	struct scatterlist sg[2];
 	struct nand_page_io_req *req;
+	unsigned int pageoffs;
 };
 
 static struct mxic_ecc_engine *ext_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
@@ -111,11 +116,19 @@ static struct mxic_ecc_engine *ext_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
 	return container_of(eng, struct mxic_ecc_engine, external_engine);
 }
 
+static struct mxic_ecc_engine *pip_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
+{
+	return container_of(eng, struct mxic_ecc_engine, pipelined_engine);
+}
+
 static struct mxic_ecc_engine *nand_to_mxic(struct nand_device *nand)
 {
 	struct nand_ecc_engine *eng = nand->ecc.engine;
 
-	return ext_ecc_eng_to_mxic(eng);
+	if (eng->integration == NAND_ECC_ENGINE_INTEGRATION_EXTERNAL)
+		return ext_ecc_eng_to_mxic(eng);
+	else
+		return pip_ecc_eng_to_mxic(eng);
 }
 
 static int mxic_ecc_ooblayout_ecc(struct mtd_info *mtd, int section,
@@ -364,6 +377,38 @@ static int mxic_ecc_init_ctx_external(struct nand_device *nand)
 	return 0;
 }
 
+static int mxic_ecc_init_ctx_pipelined(struct nand_device *nand)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx;
+	struct device *dev;
+	int ret;
+
+	dev = nand_ecc_get_engine_dev(nand->ecc.engine->dev);
+	if (!dev)
+		return -EINVAL;
+
+	dev_info(dev, "Macronix ECC engine in pipelined/mapping mode\n");
+
+	ret = mxic_ecc_init_ctx(nand, dev);
+	if (ret)
+		return ret;
+
+	ctx = nand_to_ecc_ctx(nand);
+
+	/* All steps should be handled in one go directly by the internal DMA */
+	writel(ctx->steps, mxic->regs + CHUNK_CNT);
+
+	/*
+	 * Interleaved ECC scheme cannot be used otherwise factory bad block
+	 * markers would be lost. A packed layout is mandatory.
+	 */
+	writel(BURST_TYP_INCREASING | ECC_PACKED | MAPPING,
+	       mxic->regs + HC_CONFIG);
+
+	return 0;
+}
+
 static void mxic_ecc_cleanup_ctx(struct nand_device *nand)
 {
 	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
@@ -419,6 +464,18 @@ static int mxic_ecc_process_data(struct mxic_ecc_engine *mxic,
 	return ret;
 }
 
+int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+				    unsigned int direction, dma_addr_t dirmap)
+{
+	struct mxic_ecc_engine *mxic = pip_ecc_eng_to_mxic(eng);
+
+	if (dirmap)
+		writel(dirmap, mxic->regs + HC_SLV_ADDR);
+
+	return mxic_ecc_process_data(mxic, direction);
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_process_data_pipelined);
+
 static void mxic_ecc_extract_status_bytes(struct mxic_ecc_ctx *ctx)
 {
 	u8 *buf = ctx->oobwithstat;
@@ -598,6 +655,65 @@ static int mxic_ecc_finish_io_req_external(struct nand_device *nand,
 	return mxic_ecc_count_biterrs(mxic, nand);
 }
 
+/* Pipelined ECC engine helpers */
+static int mxic_ecc_prepare_io_req_pipelined(struct nand_device *nand,
+					     struct nand_page_io_req *req)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
+	int nents;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	nand_ecc_tweak_req(&ctx->req_ctx, req);
+	ctx->req = req;
+
+	/* Copy the OOB buffer and add room for the ECC engine status bytes */
+	mxic_ecc_add_room_in_oobbuf(ctx, ctx->oobwithstat, ctx->req->oobbuf.in);
+
+	sg_set_buf(&ctx->sg[0], req->databuf.in, req->datalen);
+	sg_set_buf(&ctx->sg[1], ctx->oobwithstat,
+		   req->ooblen + (ctx->steps * STAT_BYTES));
+
+	nents = dma_map_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL);
+	if (!nents)
+		return -EINVAL;
+
+	mutex_lock(&mxic->lock);
+
+	writel(sg_dma_address(&ctx->sg[0]), mxic->regs + SDMA_MAIN_ADDR);
+	writel(sg_dma_address(&ctx->sg[1]), mxic->regs + SDMA_SPARE_ADDR);
+
+	return 0;
+}
+
+static int mxic_ecc_finish_io_req_pipelined(struct nand_device *nand,
+					    struct nand_page_io_req *req)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
+	int ret = 0;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	mutex_unlock(&mxic->lock);
+
+	dma_unmap_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL);
+
+	if (req->type == NAND_PAGE_READ) {
+		mxic_ecc_extract_status_bytes(ctx);
+		mxic_ecc_reconstruct_oobbuf(ctx, ctx->req->oobbuf.in,
+					    ctx->oobwithstat);
+		ret = mxic_ecc_count_biterrs(mxic, nand);
+	}
+
+	nand_ecc_restore_req(&ctx->req_ctx, req);
+
+	return ret;
+}
+
 static struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = {
 	.init_ctx = mxic_ecc_init_ctx_external,
 	.cleanup_ctx = mxic_ecc_cleanup_ctx,
@@ -605,6 +721,69 @@ static struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = {
 	.finish_io_req = mxic_ecc_finish_io_req_external,
 };
 
+static struct nand_ecc_engine_ops mxic_ecc_engine_pipelined_ops = {
+	.init_ctx = mxic_ecc_init_ctx_pipelined,
+	.cleanup_ctx = mxic_ecc_cleanup_ctx,
+	.prepare_io_req = mxic_ecc_prepare_io_req_pipelined,
+	.finish_io_req = mxic_ecc_finish_io_req_pipelined,
+};
+
+struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void)
+{
+	return &mxic_ecc_engine_pipelined_ops;
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_get_pipelined_ops);
+
+static struct platform_device *
+mxic_ecc_get_pdev(struct platform_device *spi_pdev)
+{
+	struct platform_device *eng_pdev;
+	struct device_node *np;
+
+	/* Retrieve the nand-ecc-engine phandle */
+	np = of_parse_phandle(spi_pdev->dev.of_node, "nand-ecc-engine", 0);
+	if (!np)
+		return NULL;
+
+	/* Jump to the engine's device node */
+	eng_pdev = of_find_device_by_node(np);
+	of_node_put(np);
+
+	return eng_pdev;
+}
+
+void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng)
+{
+	struct mxic_ecc_engine *mxic = pip_ecc_eng_to_mxic(eng);
+
+	platform_device_put(to_platform_device(mxic->dev));
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_put_pipelined_engine);
+
+struct nand_ecc_engine *
+mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev)
+{
+	struct platform_device *eng_pdev;
+	struct mxic_ecc_engine *mxic;
+
+	eng_pdev = mxic_ecc_get_pdev(spi_pdev);
+	if (!eng_pdev)
+		return ERR_PTR(-ENODEV);
+
+	mxic = platform_get_drvdata(eng_pdev);
+	if (!mxic) {
+		platform_device_put(eng_pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return &mxic->pipelined_engine;
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_get_pipelined_engine);
+
+/*
+ * Only the external ECC engine is exported as the pipelined is SoC specific, so
+ * it is registered directly by the drivers that wrap it.
+ */
 static int mxic_ecc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
diff --git a/include/linux/mtd/nand-ecc-mxic.h b/include/linux/mtd/nand-ecc-mxic.h
new file mode 100644
index 000000000000..f3aa1ac82aed
--- /dev/null
+++ b/include/linux/mtd/nand-ecc-mxic.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright © 2019 Macronix
+ * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
+ *
+ * Header for the Macronix external ECC engine.
+ */
+
+#ifndef __MTD_NAND_ECC_MXIC_H__
+#define __MTD_NAND_ECC_MXIC_H__
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+
+struct mxic_ecc_engine;
+
+#if IS_ENABLED(CONFIG_MTD_NAND_ECC_MXIC)
+
+struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void);
+struct nand_ecc_engine *mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev);
+void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng);
+int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+				    unsigned int direction, dma_addr_t dirmap);
+
+#else /* !CONFIG_MTD_NAND_ECC_MXIC */
+
+static inline struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void)
+{
+	return NULL;
+}
+
+static inline struct nand_ecc_engine *
+mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng) {}
+
+static inline int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+						  unsigned int direction,
+						  dma_addr_t dirmap)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_MXIC */
+
+#endif /* __MTD_NAND_ECC_MXIC_H__ */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 02/13] mtd: nand: mxic-ecc: Support SPI pipelined mode
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Introduce the support for another possible configuration: the ECC
engine may work as DMA master (pipelined) and move itself the data
to/from the NAND chip into the buffer, applying the necessary
corrections/computations on the fly.

This driver offers an ECC engine implementation that must be
instatiated from a SPI controller driver.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc-mxic.c       | 181 +++++++++++++++++++++++++++++-
 include/linux/mtd/nand-ecc-mxic.h |  49 ++++++++
 2 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/mtd/nand-ecc-mxic.h

diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c
index ea88a411ed70..3d2d20a6d465 100644
--- a/drivers/mtd/nand/ecc-mxic.c
+++ b/drivers/mtd/nand/ecc-mxic.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand-ecc-mxic.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
@@ -40,7 +41,9 @@
 #define INTRPT_SIG_EN 0x0C
 /* Host Controller Configuration */
 #define HC_CONFIG 0x10
+#define   DEV2MEM 0 /* TRANS_TYP_DMA in the spec */
 #define   MEM2MEM BIT(4) /* TRANS_TYP_IO in the spec */
+#define   MAPPING BIT(5) /* TRANS_TYP_MAPPING in the spec */
 #define   ECC_PACKED 0 /* LAYOUT_TYP_INTEGRATED in the spec */
 #define   ECC_INTERLEAVED BIT(2) /* LAYOUT_TYP_DISTRIBUTED in the spec */
 #define   BURST_TYP_FIXED 0
@@ -87,6 +90,7 @@ struct mxic_ecc_engine {
 	int irq;
 	struct completion complete;
 	struct nand_ecc_engine external_engine;
+	struct nand_ecc_engine pipelined_engine;
 	struct mutex lock;
 };
 
@@ -104,6 +108,7 @@ struct mxic_ecc_ctx {
 	u8 *oobwithstat;
 	struct scatterlist sg[2];
 	struct nand_page_io_req *req;
+	unsigned int pageoffs;
 };
 
 static struct mxic_ecc_engine *ext_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
@@ -111,11 +116,19 @@ static struct mxic_ecc_engine *ext_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
 	return container_of(eng, struct mxic_ecc_engine, external_engine);
 }
 
+static struct mxic_ecc_engine *pip_ecc_eng_to_mxic(struct nand_ecc_engine *eng)
+{
+	return container_of(eng, struct mxic_ecc_engine, pipelined_engine);
+}
+
 static struct mxic_ecc_engine *nand_to_mxic(struct nand_device *nand)
 {
 	struct nand_ecc_engine *eng = nand->ecc.engine;
 
-	return ext_ecc_eng_to_mxic(eng);
+	if (eng->integration == NAND_ECC_ENGINE_INTEGRATION_EXTERNAL)
+		return ext_ecc_eng_to_mxic(eng);
+	else
+		return pip_ecc_eng_to_mxic(eng);
 }
 
 static int mxic_ecc_ooblayout_ecc(struct mtd_info *mtd, int section,
@@ -364,6 +377,38 @@ static int mxic_ecc_init_ctx_external(struct nand_device *nand)
 	return 0;
 }
 
+static int mxic_ecc_init_ctx_pipelined(struct nand_device *nand)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx;
+	struct device *dev;
+	int ret;
+
+	dev = nand_ecc_get_engine_dev(nand->ecc.engine->dev);
+	if (!dev)
+		return -EINVAL;
+
+	dev_info(dev, "Macronix ECC engine in pipelined/mapping mode\n");
+
+	ret = mxic_ecc_init_ctx(nand, dev);
+	if (ret)
+		return ret;
+
+	ctx = nand_to_ecc_ctx(nand);
+
+	/* All steps should be handled in one go directly by the internal DMA */
+	writel(ctx->steps, mxic->regs + CHUNK_CNT);
+
+	/*
+	 * Interleaved ECC scheme cannot be used otherwise factory bad block
+	 * markers would be lost. A packed layout is mandatory.
+	 */
+	writel(BURST_TYP_INCREASING | ECC_PACKED | MAPPING,
+	       mxic->regs + HC_CONFIG);
+
+	return 0;
+}
+
 static void mxic_ecc_cleanup_ctx(struct nand_device *nand)
 {
 	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
@@ -419,6 +464,18 @@ static int mxic_ecc_process_data(struct mxic_ecc_engine *mxic,
 	return ret;
 }
 
+int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+				    unsigned int direction, dma_addr_t dirmap)
+{
+	struct mxic_ecc_engine *mxic = pip_ecc_eng_to_mxic(eng);
+
+	if (dirmap)
+		writel(dirmap, mxic->regs + HC_SLV_ADDR);
+
+	return mxic_ecc_process_data(mxic, direction);
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_process_data_pipelined);
+
 static void mxic_ecc_extract_status_bytes(struct mxic_ecc_ctx *ctx)
 {
 	u8 *buf = ctx->oobwithstat;
@@ -598,6 +655,65 @@ static int mxic_ecc_finish_io_req_external(struct nand_device *nand,
 	return mxic_ecc_count_biterrs(mxic, nand);
 }
 
+/* Pipelined ECC engine helpers */
+static int mxic_ecc_prepare_io_req_pipelined(struct nand_device *nand,
+					     struct nand_page_io_req *req)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
+	int nents;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	nand_ecc_tweak_req(&ctx->req_ctx, req);
+	ctx->req = req;
+
+	/* Copy the OOB buffer and add room for the ECC engine status bytes */
+	mxic_ecc_add_room_in_oobbuf(ctx, ctx->oobwithstat, ctx->req->oobbuf.in);
+
+	sg_set_buf(&ctx->sg[0], req->databuf.in, req->datalen);
+	sg_set_buf(&ctx->sg[1], ctx->oobwithstat,
+		   req->ooblen + (ctx->steps * STAT_BYTES));
+
+	nents = dma_map_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL);
+	if (!nents)
+		return -EINVAL;
+
+	mutex_lock(&mxic->lock);
+
+	writel(sg_dma_address(&ctx->sg[0]), mxic->regs + SDMA_MAIN_ADDR);
+	writel(sg_dma_address(&ctx->sg[1]), mxic->regs + SDMA_SPARE_ADDR);
+
+	return 0;
+}
+
+static int mxic_ecc_finish_io_req_pipelined(struct nand_device *nand,
+					    struct nand_page_io_req *req)
+{
+	struct mxic_ecc_engine *mxic = nand_to_mxic(nand);
+	struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand);
+	int ret = 0;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	mutex_unlock(&mxic->lock);
+
+	dma_unmap_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL);
+
+	if (req->type == NAND_PAGE_READ) {
+		mxic_ecc_extract_status_bytes(ctx);
+		mxic_ecc_reconstruct_oobbuf(ctx, ctx->req->oobbuf.in,
+					    ctx->oobwithstat);
+		ret = mxic_ecc_count_biterrs(mxic, nand);
+	}
+
+	nand_ecc_restore_req(&ctx->req_ctx, req);
+
+	return ret;
+}
+
 static struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = {
 	.init_ctx = mxic_ecc_init_ctx_external,
 	.cleanup_ctx = mxic_ecc_cleanup_ctx,
@@ -605,6 +721,69 @@ static struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = {
 	.finish_io_req = mxic_ecc_finish_io_req_external,
 };
 
+static struct nand_ecc_engine_ops mxic_ecc_engine_pipelined_ops = {
+	.init_ctx = mxic_ecc_init_ctx_pipelined,
+	.cleanup_ctx = mxic_ecc_cleanup_ctx,
+	.prepare_io_req = mxic_ecc_prepare_io_req_pipelined,
+	.finish_io_req = mxic_ecc_finish_io_req_pipelined,
+};
+
+struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void)
+{
+	return &mxic_ecc_engine_pipelined_ops;
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_get_pipelined_ops);
+
+static struct platform_device *
+mxic_ecc_get_pdev(struct platform_device *spi_pdev)
+{
+	struct platform_device *eng_pdev;
+	struct device_node *np;
+
+	/* Retrieve the nand-ecc-engine phandle */
+	np = of_parse_phandle(spi_pdev->dev.of_node, "nand-ecc-engine", 0);
+	if (!np)
+		return NULL;
+
+	/* Jump to the engine's device node */
+	eng_pdev = of_find_device_by_node(np);
+	of_node_put(np);
+
+	return eng_pdev;
+}
+
+void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng)
+{
+	struct mxic_ecc_engine *mxic = pip_ecc_eng_to_mxic(eng);
+
+	platform_device_put(to_platform_device(mxic->dev));
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_put_pipelined_engine);
+
+struct nand_ecc_engine *
+mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev)
+{
+	struct platform_device *eng_pdev;
+	struct mxic_ecc_engine *mxic;
+
+	eng_pdev = mxic_ecc_get_pdev(spi_pdev);
+	if (!eng_pdev)
+		return ERR_PTR(-ENODEV);
+
+	mxic = platform_get_drvdata(eng_pdev);
+	if (!mxic) {
+		platform_device_put(eng_pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return &mxic->pipelined_engine;
+}
+EXPORT_SYMBOL_GPL(mxic_ecc_get_pipelined_engine);
+
+/*
+ * Only the external ECC engine is exported as the pipelined is SoC specific, so
+ * it is registered directly by the drivers that wrap it.
+ */
 static int mxic_ecc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
diff --git a/include/linux/mtd/nand-ecc-mxic.h b/include/linux/mtd/nand-ecc-mxic.h
new file mode 100644
index 000000000000..f3aa1ac82aed
--- /dev/null
+++ b/include/linux/mtd/nand-ecc-mxic.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright © 2019 Macronix
+ * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
+ *
+ * Header for the Macronix external ECC engine.
+ */
+
+#ifndef __MTD_NAND_ECC_MXIC_H__
+#define __MTD_NAND_ECC_MXIC_H__
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+
+struct mxic_ecc_engine;
+
+#if IS_ENABLED(CONFIG_MTD_NAND_ECC_MXIC)
+
+struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void);
+struct nand_ecc_engine *mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev);
+void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng);
+int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+				    unsigned int direction, dma_addr_t dirmap);
+
+#else /* !CONFIG_MTD_NAND_ECC_MXIC */
+
+static inline struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void)
+{
+	return NULL;
+}
+
+static inline struct nand_ecc_engine *
+mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng) {}
+
+static inline int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
+						  unsigned int direction,
+						  dma_addr_t dirmap)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_MXIC */
+
+#endif /* __MTD_NAND_ECC_MXIC_H__ */
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 03/13] mtd: spinand: Delay a little bit the dirmap creation
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

As we will soon tweak the dirmap creation to act a little bit
differently depending on the picked ECC engine, we need to initialize
dirmaps after ECC engines. This should not have any effect as dirmaps
are not yet used at this point.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 7027c09925e2..715cad26fdef 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1209,14 +1209,6 @@ static int spinand_init(struct spinand_device *spinand)
 	if (ret)
 		goto err_free_bufs;
 
-	ret = spinand_create_dirmaps(spinand);
-	if (ret) {
-		dev_err(dev,
-			"Failed to create direct mappings for read/write operations (err = %d)\n",
-			ret);
-		goto err_manuf_cleanup;
-	}
-
 	ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
 	if (ret)
 		goto err_manuf_cleanup;
@@ -1251,6 +1243,14 @@ static int spinand_init(struct spinand_device *spinand)
 	mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
 	mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
 
+	ret = spinand_create_dirmaps(spinand);
+	if (ret) {
+		dev_err(dev,
+			"Failed to create direct mappings for read/write operations (err = %d)\n",
+			ret);
+		goto err_cleanup_ecc_engine;
+	}
+
 	return 0;
 
 err_cleanup_ecc_engine:
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 03/13] mtd: spinand: Delay a little bit the dirmap creation
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

As we will soon tweak the dirmap creation to act a little bit
differently depending on the picked ECC engine, we need to initialize
dirmaps after ECC engines. This should not have any effect as dirmaps
are not yet used at this point.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 7027c09925e2..715cad26fdef 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1209,14 +1209,6 @@ static int spinand_init(struct spinand_device *spinand)
 	if (ret)
 		goto err_free_bufs;
 
-	ret = spinand_create_dirmaps(spinand);
-	if (ret) {
-		dev_err(dev,
-			"Failed to create direct mappings for read/write operations (err = %d)\n",
-			ret);
-		goto err_manuf_cleanup;
-	}
-
 	ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
 	if (ret)
 		goto err_manuf_cleanup;
@@ -1251,6 +1243,14 @@ static int spinand_init(struct spinand_device *spinand)
 	mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
 	mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
 
+	ret = spinand_create_dirmaps(spinand);
+	if (ret) {
+		dev_err(dev,
+			"Failed to create direct mappings for read/write operations (err = %d)\n",
+			ret);
+		goto err_cleanup_ecc_engine;
+	}
+
 	return 0;
 
 err_cleanup_ecc_engine:
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

So far we check the support for:
- regular operations
- dtr operations
Soon, we will also need to check the support for ECC operations.

As the combinatorial will increase exponentially, let's gather all the
checks in a single generic function which takes a capabilities structure
as input. This new helper is supposed to be called by the currently
exported functions instead of repeating a similar implementation.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
 include/linux/spi/spi-mem.h |  8 ++++++++
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 37f4443ce9a0..4c6944d7b174 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
 	return true;
 }
 
+static bool spi_mem_generic_supports_op(struct spi_mem *mem,
+					const struct spi_mem_op *op,
+					struct spi_mem_controller_caps *caps)
+{
+	if (!caps->dtr) {
+		if (op->cmd.dtr || op->addr.dtr ||
+		    op->dummy.dtr || op->data.dtr)
+			return false;
+
+		if (op->cmd.nbytes != 1)
+			return false;
+	} else {
+		if (op->cmd.nbytes != 2)
+			return false;
+	}
+
+	return spi_mem_check_buswidth(mem, op);
+}
+
 bool spi_mem_dtr_supports_op(struct spi_mem *mem,
 			     const struct spi_mem_op *op)
 {
-	if (op->cmd.nbytes != 2)
-		return false;
+	struct spi_mem_controller_caps caps = {
+		.dtr = true,
+	};
 
-	return spi_mem_check_buswidth(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
 
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op)
 {
-	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
-		return false;
+	struct spi_mem_controller_caps caps = {};
 
-	if (op->cmd.nbytes != 1)
-		return false;
-
-	return spi_mem_check_buswidth(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
 
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..f365efcfb719 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
 	return mem->drvpriv;
 }
 
+/**
+ * struct spi_mem_controller_caps - SPI memory controller capabilities
+ * @dtr: Supports DTR operations
+ */
+struct spi_mem_controller_caps {
+	bool dtr;
+};
+
 /**
  * struct spi_controller_mem_ops - SPI memory operations
  * @adjust_op_size: shrink the data xfer of an operation to match controller's
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

So far we check the support for:
- regular operations
- dtr operations
Soon, we will also need to check the support for ECC operations.

As the combinatorial will increase exponentially, let's gather all the
checks in a single generic function which takes a capabilities structure
as input. This new helper is supposed to be called by the currently
exported functions instead of repeating a similar implementation.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
 include/linux/spi/spi-mem.h |  8 ++++++++
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 37f4443ce9a0..4c6944d7b174 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
 	return true;
 }
 
+static bool spi_mem_generic_supports_op(struct spi_mem *mem,
+					const struct spi_mem_op *op,
+					struct spi_mem_controller_caps *caps)
+{
+	if (!caps->dtr) {
+		if (op->cmd.dtr || op->addr.dtr ||
+		    op->dummy.dtr || op->data.dtr)
+			return false;
+
+		if (op->cmd.nbytes != 1)
+			return false;
+	} else {
+		if (op->cmd.nbytes != 2)
+			return false;
+	}
+
+	return spi_mem_check_buswidth(mem, op);
+}
+
 bool spi_mem_dtr_supports_op(struct spi_mem *mem,
 			     const struct spi_mem_op *op)
 {
-	if (op->cmd.nbytes != 2)
-		return false;
+	struct spi_mem_controller_caps caps = {
+		.dtr = true,
+	};
 
-	return spi_mem_check_buswidth(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
 
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op)
 {
-	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
-		return false;
+	struct spi_mem_controller_caps caps = {};
 
-	if (op->cmd.nbytes != 1)
-		return false;
-
-	return spi_mem_check_buswidth(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
 
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 85e2ff7b840d..f365efcfb719 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
 	return mem->drvpriv;
 }
 
+/**
+ * struct spi_mem_controller_caps - SPI memory controller capabilities
+ * @dtr: Supports DTR operations
+ */
+struct spi_mem_controller_caps {
+	bool dtr;
+};
+
 /**
  * struct spi_controller_mem_ops - SPI memory operations
  * @adjust_op_size: shrink the data xfer of an operation to match controller's
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 05/13] spi: spi-mem: Export the spi_mem_generic_supports_op() helper
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

The combination of checks against the number of supported operations is
going to increase exponentially each time we add a new parameter. So far
we only had a dtr parameter. Now we are introducing an ECC parameter. We
need to make this helper available for drivers with specific needs,
instead of creating yet another set of helpers each time we want to
check something new. In the future if we see that many different drivers
use the same parameter values, we might be tempted to create a specific
helper for that. But for now, let's just make the generic one
available.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       |  7 ++++---
 include/linux/spi/spi-mem.h | 12 ++++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 4c6944d7b174..df2ec2c8ce31 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -160,9 +160,9 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
 	return true;
 }
 
-static bool spi_mem_generic_supports_op(struct spi_mem *mem,
-					const struct spi_mem_op *op,
-					struct spi_mem_controller_caps *caps)
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps)
 {
 	if (!caps->dtr) {
 		if (op->cmd.dtr || op->addr.dtr ||
@@ -178,6 +178,7 @@ static bool spi_mem_generic_supports_op(struct spi_mem *mem,
 
 	return spi_mem_check_buswidth(mem, op);
 }
+EXPORT_SYMBOL_GPL(spi_mem_generic_supports_op);
 
 bool spi_mem_dtr_supports_op(struct spi_mem *mem,
 			     const struct spi_mem_op *op)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index f365efcfb719..a17dd5035530 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -325,6 +325,10 @@ void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
 					  const struct spi_mem_op *op,
 					  struct sg_table *sg);
 
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps);
+
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op);
 
@@ -347,6 +351,14 @@ spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
 {
 }
 
+static inline
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps)
+{
+	return false;
+}
+
 static inline
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 05/13] spi: spi-mem: Export the spi_mem_generic_supports_op() helper
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

The combination of checks against the number of supported operations is
going to increase exponentially each time we add a new parameter. So far
we only had a dtr parameter. Now we are introducing an ECC parameter. We
need to make this helper available for drivers with specific needs,
instead of creating yet another set of helpers each time we want to
check something new. In the future if we see that many different drivers
use the same parameter values, we might be tempted to create a specific
helper for that. But for now, let's just make the generic one
available.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       |  7 ++++---
 include/linux/spi/spi-mem.h | 12 ++++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 4c6944d7b174..df2ec2c8ce31 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -160,9 +160,9 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
 	return true;
 }
 
-static bool spi_mem_generic_supports_op(struct spi_mem *mem,
-					const struct spi_mem_op *op,
-					struct spi_mem_controller_caps *caps)
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps)
 {
 	if (!caps->dtr) {
 		if (op->cmd.dtr || op->addr.dtr ||
@@ -178,6 +178,7 @@ static bool spi_mem_generic_supports_op(struct spi_mem *mem,
 
 	return spi_mem_check_buswidth(mem, op);
 }
+EXPORT_SYMBOL_GPL(spi_mem_generic_supports_op);
 
 bool spi_mem_dtr_supports_op(struct spi_mem *mem,
 			     const struct spi_mem_op *op)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index f365efcfb719..a17dd5035530 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -325,6 +325,10 @@ void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
 					  const struct spi_mem_op *op,
 					  struct sg_table *sg);
 
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps);
+
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op);
 
@@ -347,6 +351,14 @@ spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
 {
 }
 
+static inline
+bool spi_mem_generic_supports_op(struct spi_mem *mem,
+				 const struct spi_mem_op *op,
+				 struct spi_mem_controller_caps *caps)
+{
+	return false;
+}
+
 static inline
 bool spi_mem_default_supports_op(struct spi_mem *mem,
 				 const struct spi_mem_op *op)
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 06/13] spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Soon the SPI-NAND core will need a way to request a SPI controller to
enable ECC support for a given operation. This is because of the
pipelined integration of certain ECC engines, which are directly managed
by the SPI controller itself.

Introduce a spi_mem_op additional field for this purpose: ecc_en.

So far this field is left unset and checked to be false by all
the SPI controller drivers in their ->supports_op() hook, as they all
call spi_mem_default/dtr_supports_op().

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       | 5 +++++
 include/linux/spi/spi-mem.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index df2ec2c8ce31..30a0921d5496 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -176,6 +176,11 @@ bool spi_mem_generic_supports_op(struct spi_mem *mem,
 			return false;
 	}
 
+	if (!caps->ecc) {
+		if (op->ecc_en)
+			return false;
+	}
+
 	return spi_mem_check_buswidth(mem, op);
 }
 EXPORT_SYMBOL_GPL(spi_mem_generic_supports_op);
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index a17dd5035530..a667dfc8f327 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -94,6 +94,7 @@ enum spi_mem_data_dir {
  *		 operation does not involve transferring data
  * @data.buf.in: input buffer (must be DMA-able)
  * @data.buf.out: output buffer (must be DMA-able)
+ * @ecc_en: error correction is required
  */
 struct spi_mem_op {
 	struct {
@@ -126,6 +127,8 @@ struct spi_mem_op {
 			const void *out;
 		} buf;
 	} data;
+
+	bool ecc_en;
 };
 
 #define SPI_MEM_OP(__cmd, __addr, __dummy, __data)		\
@@ -223,9 +226,11 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
 /**
  * struct spi_mem_controller_caps - SPI memory controller capabilities
  * @dtr: Supports DTR operations
+ * @ecc: Supports operations with error correction
  */
 struct spi_mem_controller_caps {
 	bool dtr;
+	bool ecc;
 };
 
 /**
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 06/13] spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Soon the SPI-NAND core will need a way to request a SPI controller to
enable ECC support for a given operation. This is because of the
pipelined integration of certain ECC engines, which are directly managed
by the SPI controller itself.

Introduce a spi_mem_op additional field for this purpose: ecc_en.

So far this field is left unset and checked to be false by all
the SPI controller drivers in their ->supports_op() hook, as they all
call spi_mem_default/dtr_supports_op().

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mem.c       | 5 +++++
 include/linux/spi/spi-mem.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index df2ec2c8ce31..30a0921d5496 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -176,6 +176,11 @@ bool spi_mem_generic_supports_op(struct spi_mem *mem,
 			return false;
 	}
 
+	if (!caps->ecc) {
+		if (op->ecc_en)
+			return false;
+	}
+
 	return spi_mem_check_buswidth(mem, op);
 }
 EXPORT_SYMBOL_GPL(spi_mem_generic_supports_op);
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index a17dd5035530..a667dfc8f327 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -94,6 +94,7 @@ enum spi_mem_data_dir {
  *		 operation does not involve transferring data
  * @data.buf.in: input buffer (must be DMA-able)
  * @data.buf.out: output buffer (must be DMA-able)
+ * @ecc_en: error correction is required
  */
 struct spi_mem_op {
 	struct {
@@ -126,6 +127,8 @@ struct spi_mem_op {
 			const void *out;
 		} buf;
 	} data;
+
+	bool ecc_en;
 };
 
 #define SPI_MEM_OP(__cmd, __addr, __dummy, __data)		\
@@ -223,9 +226,11 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
 /**
  * struct spi_mem_controller_caps - SPI memory controller capabilities
  * @dtr: Supports DTR operations
+ * @ecc: Supports operations with error correction
  */
 struct spi_mem_controller_caps {
 	bool dtr;
+	bool ecc;
 };
 
 /**
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 07/13] mtd: spinand: Create direct mapping descriptors for ECC operations
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

In order for pipelined ECC engines to be able to enable/disable the ECC
engine only when needed and avoid races when future parallel-operations
will be supported, we need to provide the information about the use of
the ECC engine in the direct mapping hooks. As direct mapping
configurations are meant to be static, it is best to create two new
mappings: one for regular 'raw' accesses and one for accesses involving
correction. It is up to the driver to use or not the new ECC enable
boolean contained in the spi-mem operation.

As dirmaps are not free (they consume a few pages of MMIO address space)
and because these extra entries are only meant to be used by pipelined
engines, let's limit their use to this specific type of engine and save
a bit of memory with all the other setups.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 35 +++++++++++++++++++++++++++++++++--
 include/linux/mtd/spinand.h |  2 ++
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 715cad26fdef..eb999e47e978 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -381,7 +381,10 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 		}
 	}
 
-	rdesc = spinand->dirmaps[req->pos.plane].rdesc;
+	if (req->mode == MTD_OPS_RAW)
+		rdesc = spinand->dirmaps[req->pos.plane].rdesc;
+	else
+		rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc;
 
 	while (nbytes) {
 		ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
@@ -452,7 +455,10 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
 			       req->ooblen);
 	}
 
-	wdesc = spinand->dirmaps[req->pos.plane].wdesc;
+	if (req->mode == MTD_OPS_RAW)
+		wdesc = spinand->dirmaps[req->pos.plane].wdesc;
+	else
+		wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc;
 
 	while (nbytes) {
 		ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf);
@@ -866,6 +872,31 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 
 	spinand->dirmaps[plane].rdesc = desc;
 
+	if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) {
+		spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc;
+		spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc;
+
+		return 0;
+	}
+
+	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl.ecc_en = true;
+	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+					  spinand->spimem, &info);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	spinand->dirmaps[plane].wdesc_ecc = desc;
+
+	info.op_tmpl = *spinand->op_templates.read_cache;
+	info.op_tmpl.ecc_en = true;
+	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+					  spinand->spimem, &info);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	spinand->dirmaps[plane].rdesc_ecc = desc;
+
 	return 0;
 }
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6988956b8492..3aa28240a77f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -389,6 +389,8 @@ struct spinand_info {
 struct spinand_dirmap {
 	struct spi_mem_dirmap_desc *wdesc;
 	struct spi_mem_dirmap_desc *rdesc;
+	struct spi_mem_dirmap_desc *wdesc_ecc;
+	struct spi_mem_dirmap_desc *rdesc_ecc;
 };
 
 /**
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 07/13] mtd: spinand: Create direct mapping descriptors for ECC operations
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

In order for pipelined ECC engines to be able to enable/disable the ECC
engine only when needed and avoid races when future parallel-operations
will be supported, we need to provide the information about the use of
the ECC engine in the direct mapping hooks. As direct mapping
configurations are meant to be static, it is best to create two new
mappings: one for regular 'raw' accesses and one for accesses involving
correction. It is up to the driver to use or not the new ECC enable
boolean contained in the spi-mem operation.

As dirmaps are not free (they consume a few pages of MMIO address space)
and because these extra entries are only meant to be used by pipelined
engines, let's limit their use to this specific type of engine and save
a bit of memory with all the other setups.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 35 +++++++++++++++++++++++++++++++++--
 include/linux/mtd/spinand.h |  2 ++
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 715cad26fdef..eb999e47e978 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -381,7 +381,10 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 		}
 	}
 
-	rdesc = spinand->dirmaps[req->pos.plane].rdesc;
+	if (req->mode == MTD_OPS_RAW)
+		rdesc = spinand->dirmaps[req->pos.plane].rdesc;
+	else
+		rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc;
 
 	while (nbytes) {
 		ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
@@ -452,7 +455,10 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
 			       req->ooblen);
 	}
 
-	wdesc = spinand->dirmaps[req->pos.plane].wdesc;
+	if (req->mode == MTD_OPS_RAW)
+		wdesc = spinand->dirmaps[req->pos.plane].wdesc;
+	else
+		wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc;
 
 	while (nbytes) {
 		ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf);
@@ -866,6 +872,31 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
 
 	spinand->dirmaps[plane].rdesc = desc;
 
+	if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) {
+		spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc;
+		spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc;
+
+		return 0;
+	}
+
+	info.op_tmpl = *spinand->op_templates.update_cache;
+	info.op_tmpl.ecc_en = true;
+	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+					  spinand->spimem, &info);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	spinand->dirmaps[plane].wdesc_ecc = desc;
+
+	info.op_tmpl = *spinand->op_templates.read_cache;
+	info.op_tmpl.ecc_en = true;
+	desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
+					  spinand->spimem, &info);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	spinand->dirmaps[plane].rdesc_ecc = desc;
+
 	return 0;
 }
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6988956b8492..3aa28240a77f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -389,6 +389,8 @@ struct spinand_info {
 struct spinand_dirmap {
 	struct spi_mem_dirmap_desc *wdesc;
 	struct spi_mem_dirmap_desc *rdesc;
+	struct spi_mem_dirmap_desc *wdesc_ecc;
+	struct spi_mem_dirmap_desc *rdesc_ecc;
 };
 
 /**
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 08/13] spi: mxic: Fix the transmit path
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal, stable, Mason Yang, Zhengxun Li

By working with external hardware ECC engines, we figured out that
Under certain circumstances, it is needed for the SPI controller to
check INT_TX_EMPTY and INT_RX_NOT_EMPTY in both receive and transmit
path (not only in the receive path). The delay penalty being
negligible, move this code in the common path.

Fixes: b942d80b0a39 ("spi: Add MXIC controller driver")
Cc: stable@vger.kernel.org
Suggested-by: Mason Yang <masonccyang@mxic.com.tw>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 45889947afed..03fce4493aa7 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -304,25 +304,21 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 
 		writel(data, mxic->regs + TXD(nbytes % 4));
 
+		ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+					 sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
+		if (ret)
+			return ret;
+
+		ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+					 sts & INT_RX_NOT_EMPTY, 0,
+					 USEC_PER_SEC);
+		if (ret)
+			return ret;
+
+		data = readl(mxic->regs + RXD);
 		if (rxbuf) {
-			ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
-						 sts & INT_TX_EMPTY, 0,
-						 USEC_PER_SEC);
-			if (ret)
-				return ret;
-
-			ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
-						 sts & INT_RX_NOT_EMPTY, 0,
-						 USEC_PER_SEC);
-			if (ret)
-				return ret;
-
-			data = readl(mxic->regs + RXD);
 			data >>= (8 * (4 - nbytes));
 			memcpy(rxbuf + pos, &data, nbytes);
-			WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
-		} else {
-			readl(mxic->regs + RXD);
 		}
 		WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 08/13] spi: mxic: Fix the transmit path
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal, stable, Mason Yang, Zhengxun Li

By working with external hardware ECC engines, we figured out that
Under certain circumstances, it is needed for the SPI controller to
check INT_TX_EMPTY and INT_RX_NOT_EMPTY in both receive and transmit
path (not only in the receive path). The delay penalty being
negligible, move this code in the common path.

Fixes: b942d80b0a39 ("spi: Add MXIC controller driver")
Cc: stable@vger.kernel.org
Suggested-by: Mason Yang <masonccyang@mxic.com.tw>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 45889947afed..03fce4493aa7 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -304,25 +304,21 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 
 		writel(data, mxic->regs + TXD(nbytes % 4));
 
+		ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+					 sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
+		if (ret)
+			return ret;
+
+		ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+					 sts & INT_RX_NOT_EMPTY, 0,
+					 USEC_PER_SEC);
+		if (ret)
+			return ret;
+
+		data = readl(mxic->regs + RXD);
 		if (rxbuf) {
-			ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
-						 sts & INT_TX_EMPTY, 0,
-						 USEC_PER_SEC);
-			if (ret)
-				return ret;
-
-			ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
-						 sts & INT_RX_NOT_EMPTY, 0,
-						 USEC_PER_SEC);
-			if (ret)
-				return ret;
-
-			data = readl(mxic->regs + RXD);
 			data >>= (8 * (4 - nbytes));
 			memcpy(rxbuf + pos, &data, nbytes);
-			WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
-		} else {
-			readl(mxic->regs + RXD);
 		}
 		WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY);
 
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 09/13] spi: mxic: Create a helper to configure the controller before an operation
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Create the mxic_spi_set_hc_cfg() helper to configure the HC_CFG
register. This helper will soon be used by the dirmap implementation and
having this code factorized out earlier will clarify this addition.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 03fce4493aa7..068543c40ce7 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -280,6 +280,22 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
 	       mxic->regs + HC_CFG);
 }
 
+static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
+{
+	int nio = 1;
+
+	if (spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL))
+		nio = 8;
+	else if (spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
+		nio = 4;
+	else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
+		nio = 2;
+
+	return flags | HC_CFG_NIO(nio) |
+	       HC_CFG_TYPE(spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
+	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
+}
+
 static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 			      void *rxbuf, unsigned int len)
 {
@@ -357,7 +373,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 				const struct spi_mem_op *op)
 {
 	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
-	int nio = 1, i, ret;
+	int i, ret;
 	u32 ss_ctrl;
 	u8 addr[8], cmd[2];
 
@@ -365,18 +381,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 	if (ret)
 		return ret;
 
-	if (mem->spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL))
-		nio = 8;
-	else if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
-		nio = 4;
-	else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
-		nio = 2;
-
-	writel(HC_CFG_NIO(nio) |
-	       HC_CFG_TYPE(mem->spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
-	       HC_CFG_SLV_ACT(mem->spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1) |
-	       HC_CFG_MAN_CS_EN,
+	writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
 	       mxic->regs + HC_CFG);
+
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
 	ss_ctrl = OP_CMD_BYTES(op->cmd.nbytes) |
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 09/13] spi: mxic: Create a helper to configure the controller before an operation
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Create the mxic_spi_set_hc_cfg() helper to configure the HC_CFG
register. This helper will soon be used by the dirmap implementation and
having this code factorized out earlier will clarify this addition.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 03fce4493aa7..068543c40ce7 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -280,6 +280,22 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
 	       mxic->regs + HC_CFG);
 }
 
+static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
+{
+	int nio = 1;
+
+	if (spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL))
+		nio = 8;
+	else if (spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
+		nio = 4;
+	else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
+		nio = 2;
+
+	return flags | HC_CFG_NIO(nio) |
+	       HC_CFG_TYPE(spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
+	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
+}
+
 static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 			      void *rxbuf, unsigned int len)
 {
@@ -357,7 +373,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 				const struct spi_mem_op *op)
 {
 	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
-	int nio = 1, i, ret;
+	int i, ret;
 	u32 ss_ctrl;
 	u8 addr[8], cmd[2];
 
@@ -365,18 +381,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 	if (ret)
 		return ret;
 
-	if (mem->spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL))
-		nio = 8;
-	else if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD))
-		nio = 4;
-	else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
-		nio = 2;
-
-	writel(HC_CFG_NIO(nio) |
-	       HC_CFG_TYPE(mem->spi->chip_select, HC_CFG_TYPE_SPI_NOR) |
-	       HC_CFG_SLV_ACT(mem->spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1) |
-	       HC_CFG_MAN_CS_EN,
+	writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
 	       mxic->regs + HC_CFG);
+
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
 	ss_ctrl = OP_CMD_BYTES(op->cmd.nbytes) |
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 10/13] spi: mxic: Create a helper to ease the start of an operation
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Create the mxic_spi_mem_prep_op_cfg() helper to provide the content to
write to the register controlling the next IO command. This helper will
soon be used by the dirmap implementation and having this code
factorized out earlier will clarify this addition.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 53 +++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 068543c40ce7..3c4e64cbe812 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -296,6 +296,33 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
 	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
 }
 
+static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
+{
+	u32 cfg = OP_CMD_BYTES(op->cmd.nbytes) |
+		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
+		  (op->cmd.dtr ? OP_CMD_DDR : 0);
+
+	if (op->addr.nbytes)
+		cfg |= OP_ADDR_BYTES(op->addr.nbytes) |
+		       OP_ADDR_BUSW(fls(op->addr.buswidth) - 1) |
+		       (op->addr.dtr ? OP_ADDR_DDR : 0);
+
+	if (op->dummy.nbytes)
+		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
+
+	if (op->data.nbytes) {
+		cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
+		       (op->data.dtr ? OP_DATA_DDR : 0);
+		if (op->data.dir == SPI_MEM_DATA_IN) {
+			cfg |= OP_READ;
+			if (op->data.dtr)
+				cfg |= OP_DQS_EN;
+		}
+	}
+
+	return cfg;
+}
+
 static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 			      void *rxbuf, unsigned int len)
 {
@@ -374,7 +401,6 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 {
 	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
 	int i, ret;
-	u32 ss_ctrl;
 	u8 addr[8], cmd[2];
 
 	ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
@@ -386,29 +412,8 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
-	ss_ctrl = OP_CMD_BYTES(op->cmd.nbytes) |
-		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
-		  (op->cmd.dtr ? OP_CMD_DDR : 0);
-
-	if (op->addr.nbytes)
-		ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) |
-			   OP_ADDR_BUSW(fls(op->addr.buswidth) - 1) |
-			   (op->addr.dtr ? OP_ADDR_DDR : 0);
-
-	if (op->dummy.nbytes)
-		ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes);
-
-	if (op->data.nbytes) {
-		ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
-			   (op->data.dtr ? OP_DATA_DDR : 0);
-		if (op->data.dir == SPI_MEM_DATA_IN) {
-			ss_ctrl |= OP_READ;
-			if (op->data.dtr)
-				ss_ctrl |= OP_DQS_EN;
-		}
-	}
-
-	writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select));
+	writel(mxic_spi_mem_prep_op_cfg(op),
+	       mxic->regs + SS_CTRL(mem->spi->chip_select));
 
 	writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
 	       mxic->regs + HC_CFG);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 10/13] spi: mxic: Create a helper to ease the start of an operation
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Create the mxic_spi_mem_prep_op_cfg() helper to provide the content to
write to the register controlling the next IO command. This helper will
soon be used by the dirmap implementation and having this code
factorized out earlier will clarify this addition.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 53 +++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 068543c40ce7..3c4e64cbe812 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -296,6 +296,33 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
 	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
 }
 
+static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
+{
+	u32 cfg = OP_CMD_BYTES(op->cmd.nbytes) |
+		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
+		  (op->cmd.dtr ? OP_CMD_DDR : 0);
+
+	if (op->addr.nbytes)
+		cfg |= OP_ADDR_BYTES(op->addr.nbytes) |
+		       OP_ADDR_BUSW(fls(op->addr.buswidth) - 1) |
+		       (op->addr.dtr ? OP_ADDR_DDR : 0);
+
+	if (op->dummy.nbytes)
+		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
+
+	if (op->data.nbytes) {
+		cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
+		       (op->data.dtr ? OP_DATA_DDR : 0);
+		if (op->data.dir == SPI_MEM_DATA_IN) {
+			cfg |= OP_READ;
+			if (op->data.dtr)
+				cfg |= OP_DQS_EN;
+		}
+	}
+
+	return cfg;
+}
+
 static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 			      void *rxbuf, unsigned int len)
 {
@@ -374,7 +401,6 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 {
 	struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
 	int i, ret;
-	u32 ss_ctrl;
 	u8 addr[8], cmd[2];
 
 	ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
@@ -386,29 +412,8 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
-	ss_ctrl = OP_CMD_BYTES(op->cmd.nbytes) |
-		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
-		  (op->cmd.dtr ? OP_CMD_DDR : 0);
-
-	if (op->addr.nbytes)
-		ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) |
-			   OP_ADDR_BUSW(fls(op->addr.buswidth) - 1) |
-			   (op->addr.dtr ? OP_ADDR_DDR : 0);
-
-	if (op->dummy.nbytes)
-		ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes);
-
-	if (op->data.nbytes) {
-		ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
-			   (op->data.dtr ? OP_DATA_DDR : 0);
-		if (op->data.dir == SPI_MEM_DATA_IN) {
-			ss_ctrl |= OP_READ;
-			if (op->data.dtr)
-				ss_ctrl |= OP_DQS_EN;
-		}
-	}
-
-	writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select));
+	writel(mxic_spi_mem_prep_op_cfg(op),
+	       mxic->regs + SS_CTRL(mem->spi->chip_select));
 
 	writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
 	       mxic->regs + HC_CFG);
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 11/13] spi: mxic: Add support for direct mapping
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal, Zhengxun Li

Implement the ->dirmap_create() and ->dirmap_read/write() hooks to
provide a fast path for read and write accesses.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Tested-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 112 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 109 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 3c4e64cbe812..485a7f2afb44 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -172,6 +172,11 @@ struct mxic_spi {
 	struct clk *send_dly_clk;
 	void __iomem *regs;
 	u32 cur_speed_hz;
+	struct {
+		void __iomem *map;
+		dma_addr_t dma;
+		size_t size;
+	} linear;
 };
 
 static int mxic_spi_clk_enable(struct mxic_spi *mxic)
@@ -296,7 +301,8 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
 	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
 }
 
-static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
+static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
+				    unsigned int data_len)
 {
 	u32 cfg = OP_CMD_BYTES(op->cmd.nbytes) |
 		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
@@ -310,7 +316,8 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
 	if (op->dummy.nbytes)
 		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
 
-	if (op->data.nbytes) {
+	/* Direct mapping data.nbytes field is not populated */
+	if (data_len) {
 		cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
 		       (op->data.dtr ? OP_DATA_DDR : 0);
 		if (op->data.dir == SPI_MEM_DATA_IN) {
@@ -371,6 +378,77 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 	return 0;
 }
 
+static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+					u64 offs, size_t len, void *buf)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+	int ret;
+	u32 sts;
+
+	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
+		return -EINVAL;
+
+	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+
+	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
+	       mxic->regs + LRD_CFG);
+	writel(desc->info.offset + offs, mxic->regs + LRD_ADDR);
+	len = min_t(size_t, len, mxic->linear.size);
+	writel(len, mxic->regs + LRD_RANGE);
+	writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
+	       LMODE_SLV_ACT(desc->mem->spi->chip_select) |
+	       LMODE_EN,
+	       mxic->regs + LRD_CTRL);
+
+	memcpy_fromio(buf, mxic->linear.map, len);
+
+	writel(INT_LRD_DIS, mxic->regs + INT_STS);
+	writel(0, mxic->regs + LRD_CTRL);
+
+	ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+				 sts & INT_LRD_DIS, 0, USEC_PER_SEC);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+					 u64 offs, size_t len,
+					 const void *buf)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+	u32 sts;
+	int ret;
+
+	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
+		return -EINVAL;
+
+	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+
+	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
+	       mxic->regs + LWR_CFG);
+	writel(desc->info.offset + offs, mxic->regs + LWR_ADDR);
+	len = min_t(size_t, len, mxic->linear.size);
+	writel(len, mxic->regs + LWR_RANGE);
+	writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
+	       LMODE_SLV_ACT(desc->mem->spi->chip_select) |
+	       LMODE_EN,
+	       mxic->regs + LWR_CTRL);
+
+	memcpy_toio(mxic->linear.map, buf, len);
+
+	writel(INT_LWR_DIS, mxic->regs + INT_STS);
+	writel(0, mxic->regs + LWR_CTRL);
+
+	ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+				 sts & INT_LWR_DIS, 0, USEC_PER_SEC);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
 static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 				     const struct spi_mem_op *op)
 {
@@ -396,6 +474,22 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 		return spi_mem_dtr_supports_op(mem, op);
 }
 
+static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+
+	if (!mxic->linear.map)
+		return -EINVAL;
+
+	if (desc->info.offset + desc->info.length > U32_MAX)
+		return -EINVAL;
+
+	if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
 static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 				const struct spi_mem_op *op)
 {
@@ -412,7 +506,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
-	writel(mxic_spi_mem_prep_op_cfg(op),
+	writel(mxic_spi_mem_prep_op_cfg(op, op->data.nbytes),
 	       mxic->regs + SS_CTRL(mem->spi->chip_select));
 
 	writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
@@ -454,6 +548,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
 	.supports_op = mxic_spi_mem_supports_op,
 	.exec_op = mxic_spi_mem_exec_op,
+	.dirmap_create = mxic_spi_mem_dirmap_create,
+	.dirmap_read = mxic_spi_mem_dirmap_read,
+	.dirmap_write = mxic_spi_mem_dirmap_write,
 };
 
 static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
@@ -583,6 +680,15 @@ static int mxic_spi_probe(struct platform_device *pdev)
 	if (IS_ERR(mxic->regs))
 		return PTR_ERR(mxic->regs);
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
+	mxic->linear.map = devm_ioremap_resource(&pdev->dev, res);
+	if (!IS_ERR(mxic->linear.map)) {
+		mxic->linear.dma = res->start;
+		mxic->linear.size = resource_size(res);
+	} else {
+		mxic->linear.map = NULL;
+	}
+
 	pm_runtime_enable(&pdev->dev);
 	master->auto_runtime_pm = true;
 
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 11/13] spi: mxic: Add support for direct mapping
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal, Zhengxun Li

Implement the ->dirmap_create() and ->dirmap_read/write() hooks to
provide a fast path for read and write accesses.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Tested-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Zhengxun Li <zhengxunli@mxic.com.tw>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-mxic.c | 112 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 109 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 3c4e64cbe812..485a7f2afb44 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -172,6 +172,11 @@ struct mxic_spi {
 	struct clk *send_dly_clk;
 	void __iomem *regs;
 	u32 cur_speed_hz;
+	struct {
+		void __iomem *map;
+		dma_addr_t dma;
+		size_t size;
+	} linear;
 };
 
 static int mxic_spi_clk_enable(struct mxic_spi *mxic)
@@ -296,7 +301,8 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
 	       HC_CFG_SLV_ACT(spi->chip_select) | HC_CFG_IDLE_SIO_LVL(1);
 }
 
-static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
+static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op,
+				    unsigned int data_len)
 {
 	u32 cfg = OP_CMD_BYTES(op->cmd.nbytes) |
 		  OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) |
@@ -310,7 +316,8 @@ static u32 mxic_spi_mem_prep_op_cfg(const struct spi_mem_op *op)
 	if (op->dummy.nbytes)
 		cfg |= OP_DUMMY_CYC(op->dummy.nbytes);
 
-	if (op->data.nbytes) {
+	/* Direct mapping data.nbytes field is not populated */
+	if (data_len) {
 		cfg |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) |
 		       (op->data.dtr ? OP_DATA_DDR : 0);
 		if (op->data.dir == SPI_MEM_DATA_IN) {
@@ -371,6 +378,77 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
 	return 0;
 }
 
+static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
+					u64 offs, size_t len, void *buf)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+	int ret;
+	u32 sts;
+
+	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
+		return -EINVAL;
+
+	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+
+	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
+	       mxic->regs + LRD_CFG);
+	writel(desc->info.offset + offs, mxic->regs + LRD_ADDR);
+	len = min_t(size_t, len, mxic->linear.size);
+	writel(len, mxic->regs + LRD_RANGE);
+	writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
+	       LMODE_SLV_ACT(desc->mem->spi->chip_select) |
+	       LMODE_EN,
+	       mxic->regs + LRD_CTRL);
+
+	memcpy_fromio(buf, mxic->linear.map, len);
+
+	writel(INT_LRD_DIS, mxic->regs + INT_STS);
+	writel(0, mxic->regs + LRD_CTRL);
+
+	ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+				 sts & INT_LRD_DIS, 0, USEC_PER_SEC);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+					 u64 offs, size_t len,
+					 const void *buf)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+	u32 sts;
+	int ret;
+
+	if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
+		return -EINVAL;
+
+	writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+
+	writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
+	       mxic->regs + LWR_CFG);
+	writel(desc->info.offset + offs, mxic->regs + LWR_ADDR);
+	len = min_t(size_t, len, mxic->linear.size);
+	writel(len, mxic->regs + LWR_RANGE);
+	writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) |
+	       LMODE_SLV_ACT(desc->mem->spi->chip_select) |
+	       LMODE_EN,
+	       mxic->regs + LWR_CTRL);
+
+	memcpy_toio(mxic->linear.map, buf, len);
+
+	writel(INT_LWR_DIS, mxic->regs + INT_STS);
+	writel(0, mxic->regs + LWR_CTRL);
+
+	ret = readl_poll_timeout(mxic->regs + INT_STS, sts,
+				 sts & INT_LWR_DIS, 0, USEC_PER_SEC);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
 static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 				     const struct spi_mem_op *op)
 {
@@ -396,6 +474,22 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 		return spi_mem_dtr_supports_op(mem, op);
 }
 
+static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+
+	if (!mxic->linear.map)
+		return -EINVAL;
+
+	if (desc->info.offset + desc->info.length > U32_MAX)
+		return -EINVAL;
+
+	if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
 static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 				const struct spi_mem_op *op)
 {
@@ -412,7 +506,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 
 	writel(HC_EN_BIT, mxic->regs + HC_EN);
 
-	writel(mxic_spi_mem_prep_op_cfg(op),
+	writel(mxic_spi_mem_prep_op_cfg(op, op->data.nbytes),
 	       mxic->regs + SS_CTRL(mem->spi->chip_select));
 
 	writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
@@ -454,6 +548,9 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
 static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
 	.supports_op = mxic_spi_mem_supports_op,
 	.exec_op = mxic_spi_mem_exec_op,
+	.dirmap_create = mxic_spi_mem_dirmap_create,
+	.dirmap_read = mxic_spi_mem_dirmap_read,
+	.dirmap_write = mxic_spi_mem_dirmap_write,
 };
 
 static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
@@ -583,6 +680,15 @@ static int mxic_spi_probe(struct platform_device *pdev)
 	if (IS_ERR(mxic->regs))
 		return PTR_ERR(mxic->regs);
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
+	mxic->linear.map = devm_ioremap_resource(&pdev->dev, res);
+	if (!IS_ERR(mxic->linear.map)) {
+		mxic->linear.dma = res->start;
+		mxic->linear.size = resource_size(res);
+	} else {
+		mxic->linear.map = NULL;
+	}
+
 	pm_runtime_enable(&pdev->dev);
 	master->auto_runtime_pm = true;
 
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

This driver can be simplified a little bit by using
spi_mem_generic_supports_op() instead of the
spi_mem_default/dtr_supports_op() couple. The all_false boolean is
inverted to become a dtr boolean, which checks if at least one of the
operation member uses dtr mode. The idea behind this change is to
simplify the introduction of the pipelined ECC engine.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mxic.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 485a7f2afb44..5e71aa630504 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 				     const struct spi_mem_op *op)
 {
-	bool all_false;
+	struct spi_mem_controller_caps caps = {};
 
 	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
 	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
@@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 	if (op->addr.nbytes > 7)
 		return false;
 
-	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
-		    !op->data.dtr;
+	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
 
-	if (all_false)
-		return spi_mem_default_supports_op(mem, op);
-	else
-		return spi_mem_dtr_supports_op(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 
 static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

This driver can be simplified a little bit by using
spi_mem_generic_supports_op() instead of the
spi_mem_default/dtr_supports_op() couple. The all_false boolean is
inverted to become a dtr boolean, which checks if at least one of the
operation member uses dtr mode. The idea behind this change is to
simplify the introduction of the pipelined ECC engine.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/spi/spi-mxic.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 485a7f2afb44..5e71aa630504 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 				     const struct spi_mem_op *op)
 {
-	bool all_false;
+	struct spi_mem_controller_caps caps = {};
 
 	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
 	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
@@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 	if (op->addr.nbytes > 7)
 		return false;
 
-	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
-		    !op->data.dtr;
+	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
 
-	if (all_false)
-		return spi_mem_default_supports_op(mem, op);
-	else
-		return spi_mem_dtr_supports_op(mem, op);
+	return spi_mem_generic_supports_op(mem, op, &caps);
 }
 
 static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 13/13] spi: mxic: Add support for pipelined ECC operations
  2021-12-14 11:41 ` Miquel Raynal
@ 2021-12-14 11:41   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Some SPI-NAND chips do not have a proper on-die ECC engine providing
error correction/detection. This is particularly an issue on embedded
devices with limited resources because all the computations must
happen in software, unless an external hardware engine is provided.

These external engines are new and can be of two categories: external
or pipelined. Macronix is providing both, the former being already
supported. The second, however, is very SoC implementation dependent
and must be instantiated by the SPI host controller directly.

An entire subsystem has been contributed to support these engines which
makes the insertion into another subsystem such as SPI quite
straightforward without the need for a lot of specific functions.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/Kconfig    |   2 +-
 drivers/spi/spi-mxic.c | 113 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 112 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83e352b0c8f9..bff75629e872 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -856,7 +856,7 @@ config SPI_SYNQUACER
 
 config SPI_MXIC
 	tristate "Macronix MX25F0A SPI controller"
-	depends on SPI_MASTER
+	depends on SPI_MASTER && MTD_NAND_ECC
 	help
 	  This selects the Macronix MX25F0A SPI controller driver.
 
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 5e71aa630504..74bbf0701616 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -12,6 +12,8 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand-ecc-mxic.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
@@ -167,6 +169,7 @@
 #define HW_TEST(x)		(0xe0 + ((x) * 4))
 
 struct mxic_spi {
+	struct device *dev;
 	struct clk *ps_clk;
 	struct clk *send_clk;
 	struct clk *send_dly_clk;
@@ -177,6 +180,12 @@ struct mxic_spi {
 		dma_addr_t dma;
 		size_t size;
 	} linear;
+
+	struct {
+		bool use_pipelined_conf;
+		struct nand_ecc_engine *pipelined_engine;
+		void *ctx;
+	} ecc;
 };
 
 static int mxic_spi_clk_enable(struct mxic_spi *mxic)
@@ -400,7 +409,15 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
 	       LMODE_EN,
 	       mxic->regs + LRD_CTRL);
 
-	memcpy_fromio(buf, mxic->linear.map, len);
+	if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.ecc_en) {
+		ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine,
+						      NAND_PAGE_READ,
+						      mxic->linear.dma + offs);
+		if (ret)
+			return ret;
+	} else {
+		memcpy_fromio(buf, mxic->linear.map, len);
+	}
 
 	writel(INT_LRD_DIS, mxic->regs + INT_STS);
 	writel(0, mxic->regs + LRD_CTRL);
@@ -436,7 +453,15 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 	       LMODE_EN,
 	       mxic->regs + LWR_CTRL);
 
-	memcpy_toio(mxic->linear.map, buf, len);
+	if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.ecc_en) {
+		ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine,
+						      NAND_PAGE_WRITE,
+						      mxic->linear.dma + offs);
+		if (ret)
+			return ret;
+	} else {
+		memcpy_toio(mxic->linear.map, buf, len);
+	}
 
 	writel(INT_LWR_DIS, mxic->regs + INT_STS);
 	writel(0, mxic->regs + LWR_CTRL);
@@ -466,6 +491,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 		return false;
 
 	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
+	caps.ecc = op->ecc_en;
 
 	return spi_mem_generic_supports_op(mem, op, &caps);
 }
@@ -611,6 +637,80 @@ static int mxic_spi_transfer_one(struct spi_master *master,
 	return 0;
 }
 
+/* ECC wrapper */
+static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+	struct mxic_spi *mxic = nand->ecc.engine->priv;
+
+	mxic->ecc.use_pipelined_conf = true;
+
+	return ops->init_ctx(nand);
+}
+
+static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+	struct mxic_spi *mxic = nand->ecc.engine->priv;
+
+	mxic->ecc.use_pipelined_conf = false;
+
+	ops->cleanup_ctx(nand);
+}
+
+static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand,
+					   struct nand_page_io_req *req)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+
+	return ops->prepare_io_req(nand, req);
+}
+
+static int mxic_spi_mem_ecc_finish_io_req(struct nand_device *nand,
+					  struct nand_page_io_req *req)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+
+	return ops->finish_io_req(nand, req);
+}
+
+static struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = {
+	.init_ctx = mxic_spi_mem_ecc_init_ctx,
+	.cleanup_ctx = mxic_spi_mem_ecc_cleanup_ctx,
+	.prepare_io_req = mxic_spi_mem_ecc_prepare_io_req,
+	.finish_io_req = mxic_spi_mem_ecc_finish_io_req,
+};
+
+static void mxic_spi_mem_ecc_remove(struct mxic_spi *mxic)
+{
+	if (mxic->ecc.pipelined_engine) {
+		mxic_ecc_put_pipelined_engine(mxic->ecc.pipelined_engine);
+		nand_ecc_unregister_on_host_hw_engine(mxic->ecc.pipelined_engine);
+	}
+}
+
+static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
+				  struct mxic_spi *mxic)
+{
+	struct nand_ecc_engine *eng;
+
+	if (!mxic_ecc_get_pipelined_ops())
+		return -EOPNOTSUPP;
+
+	eng = mxic_ecc_get_pipelined_engine(pdev);
+	if (IS_ERR(eng))
+		return PTR_ERR(eng);
+
+	eng->dev = &pdev->dev;
+	eng->integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
+	eng->ops = &mxic_spi_mem_ecc_engine_pipelined_ops;
+	eng->priv = mxic;
+	mxic->ecc.pipelined_engine = eng;
+	nand_ecc_register_on_host_hw_engine(eng);
+
+	return 0;
+}
+
 static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
 {
 	struct spi_master *master = dev_get_drvdata(dev);
@@ -656,6 +756,7 @@ static int mxic_spi_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, master);
 
 	mxic = spi_master_get_devdata(master);
+	mxic->dev = &pdev->dev;
 
 	master->dev.of_node = pdev->dev.of_node;
 
@@ -701,6 +802,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
 
 	mxic_spi_hw_init(mxic);
 
+	ret = mxic_spi_mem_ecc_probe(pdev, mxic);
+	if (ret == -EPROBE_DEFER) {
+		pm_runtime_disable(&pdev->dev);
+		return ret;
+	}
+
 	ret = spi_register_master(master);
 	if (ret) {
 		dev_err(&pdev->dev, "spi_register_master failed\n");
@@ -713,8 +820,10 @@ static int mxic_spi_probe(struct platform_device *pdev)
 static int mxic_spi_remove(struct platform_device *pdev)
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 
 	pm_runtime_disable(&pdev->dev);
+	mxic_spi_mem_ecc_remove(mxic);
 	spi_unregister_master(master);
 
 	return 0;
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 13/13] spi: mxic: Add support for pipelined ECC operations
@ 2021-12-14 11:41   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-14 11:41 UTC (permalink / raw)
  To: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi
  Cc: Julien Su, Jaime Liao, Thomas Petazzoni, Boris Brezillon,
	Xiangsheng Hou, Miquel Raynal

Some SPI-NAND chips do not have a proper on-die ECC engine providing
error correction/detection. This is particularly an issue on embedded
devices with limited resources because all the computations must
happen in software, unless an external hardware engine is provided.

These external engines are new and can be of two categories: external
or pipelined. Macronix is providing both, the former being already
supported. The second, however, is very SoC implementation dependent
and must be instantiated by the SPI host controller directly.

An entire subsystem has been contributed to support these engines which
makes the insertion into another subsystem such as SPI quite
straightforward without the need for a lot of specific functions.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/Kconfig    |   2 +-
 drivers/spi/spi-mxic.c | 113 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 112 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83e352b0c8f9..bff75629e872 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -856,7 +856,7 @@ config SPI_SYNQUACER
 
 config SPI_MXIC
 	tristate "Macronix MX25F0A SPI controller"
-	depends on SPI_MASTER
+	depends on SPI_MASTER && MTD_NAND_ECC
 	help
 	  This selects the Macronix MX25F0A SPI controller driver.
 
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 5e71aa630504..74bbf0701616 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -12,6 +12,8 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand-ecc-mxic.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
@@ -167,6 +169,7 @@
 #define HW_TEST(x)		(0xe0 + ((x) * 4))
 
 struct mxic_spi {
+	struct device *dev;
 	struct clk *ps_clk;
 	struct clk *send_clk;
 	struct clk *send_dly_clk;
@@ -177,6 +180,12 @@ struct mxic_spi {
 		dma_addr_t dma;
 		size_t size;
 	} linear;
+
+	struct {
+		bool use_pipelined_conf;
+		struct nand_ecc_engine *pipelined_engine;
+		void *ctx;
+	} ecc;
 };
 
 static int mxic_spi_clk_enable(struct mxic_spi *mxic)
@@ -400,7 +409,15 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
 	       LMODE_EN,
 	       mxic->regs + LRD_CTRL);
 
-	memcpy_fromio(buf, mxic->linear.map, len);
+	if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.ecc_en) {
+		ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine,
+						      NAND_PAGE_READ,
+						      mxic->linear.dma + offs);
+		if (ret)
+			return ret;
+	} else {
+		memcpy_fromio(buf, mxic->linear.map, len);
+	}
 
 	writel(INT_LRD_DIS, mxic->regs + INT_STS);
 	writel(0, mxic->regs + LRD_CTRL);
@@ -436,7 +453,15 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
 	       LMODE_EN,
 	       mxic->regs + LWR_CTRL);
 
-	memcpy_toio(mxic->linear.map, buf, len);
+	if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.ecc_en) {
+		ret = mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine,
+						      NAND_PAGE_WRITE,
+						      mxic->linear.dma + offs);
+		if (ret)
+			return ret;
+	} else {
+		memcpy_toio(mxic->linear.map, buf, len);
+	}
 
 	writel(INT_LWR_DIS, mxic->regs + INT_STS);
 	writel(0, mxic->regs + LWR_CTRL);
@@ -466,6 +491,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
 		return false;
 
 	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
+	caps.ecc = op->ecc_en;
 
 	return spi_mem_generic_supports_op(mem, op, &caps);
 }
@@ -611,6 +637,80 @@ static int mxic_spi_transfer_one(struct spi_master *master,
 	return 0;
 }
 
+/* ECC wrapper */
+static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+	struct mxic_spi *mxic = nand->ecc.engine->priv;
+
+	mxic->ecc.use_pipelined_conf = true;
+
+	return ops->init_ctx(nand);
+}
+
+static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+	struct mxic_spi *mxic = nand->ecc.engine->priv;
+
+	mxic->ecc.use_pipelined_conf = false;
+
+	ops->cleanup_ctx(nand);
+}
+
+static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand,
+					   struct nand_page_io_req *req)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+
+	return ops->prepare_io_req(nand, req);
+}
+
+static int mxic_spi_mem_ecc_finish_io_req(struct nand_device *nand,
+					  struct nand_page_io_req *req)
+{
+	struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+
+	return ops->finish_io_req(nand, req);
+}
+
+static struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = {
+	.init_ctx = mxic_spi_mem_ecc_init_ctx,
+	.cleanup_ctx = mxic_spi_mem_ecc_cleanup_ctx,
+	.prepare_io_req = mxic_spi_mem_ecc_prepare_io_req,
+	.finish_io_req = mxic_spi_mem_ecc_finish_io_req,
+};
+
+static void mxic_spi_mem_ecc_remove(struct mxic_spi *mxic)
+{
+	if (mxic->ecc.pipelined_engine) {
+		mxic_ecc_put_pipelined_engine(mxic->ecc.pipelined_engine);
+		nand_ecc_unregister_on_host_hw_engine(mxic->ecc.pipelined_engine);
+	}
+}
+
+static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
+				  struct mxic_spi *mxic)
+{
+	struct nand_ecc_engine *eng;
+
+	if (!mxic_ecc_get_pipelined_ops())
+		return -EOPNOTSUPP;
+
+	eng = mxic_ecc_get_pipelined_engine(pdev);
+	if (IS_ERR(eng))
+		return PTR_ERR(eng);
+
+	eng->dev = &pdev->dev;
+	eng->integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
+	eng->ops = &mxic_spi_mem_ecc_engine_pipelined_ops;
+	eng->priv = mxic;
+	mxic->ecc.pipelined_engine = eng;
+	nand_ecc_register_on_host_hw_engine(eng);
+
+	return 0;
+}
+
 static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
 {
 	struct spi_master *master = dev_get_drvdata(dev);
@@ -656,6 +756,7 @@ static int mxic_spi_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, master);
 
 	mxic = spi_master_get_devdata(master);
+	mxic->dev = &pdev->dev;
 
 	master->dev.of_node = pdev->dev.of_node;
 
@@ -701,6 +802,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
 
 	mxic_spi_hw_init(mxic);
 
+	ret = mxic_spi_mem_ecc_probe(pdev, mxic);
+	if (ret == -EPROBE_DEFER) {
+		pm_runtime_disable(&pdev->dev);
+		return ret;
+	}
+
 	ret = spi_register_master(master);
 	if (ret) {
 		dev_err(&pdev->dev, "spi_register_master failed\n");
@@ -713,8 +820,10 @@ static int mxic_spi_probe(struct platform_device *pdev)
 static int mxic_spi_remove(struct platform_device *pdev)
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
+	struct mxic_spi *mxic = spi_master_get_devdata(master);
 
 	pm_runtime_disable(&pdev->dev);
+	mxic_spi_mem_ecc_remove(mxic);
 	spi_unregister_master(master);
 
 	return 0;
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-14 11:41   ` Miquel Raynal
@ 2021-12-14 16:24     ` Boris Brezillon
  -1 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-14 16:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Tue, 14 Dec 2021 12:41:39 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> This driver can be simplified a little bit by using
> spi_mem_generic_supports_op() instead of the
> spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> inverted to become a dtr boolean, which checks if at least one of the
> operation member uses dtr mode. The idea behind this change is to
> simplify the introduction of the pipelined ECC engine.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/spi/spi-mxic.c | 10 +++-------
>  1 file changed, 3 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> index 485a7f2afb44..5e71aa630504 100644
> --- a/drivers/spi/spi-mxic.c
> +++ b/drivers/spi/spi-mxic.c
> @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
>  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  				     const struct spi_mem_op *op)
>  {
> -	bool all_false;
> +	struct spi_mem_controller_caps caps = {};
>  
>  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
>  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  	if (op->addr.nbytes > 7)
>  		return false;
>  
> -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> -		    !op->data.dtr;
> +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;

Are you sure that's what you want to do? spi_mem_controller_caps is
supposed to encode the controller capabilities, not whether the
operation contains a DTR cycle or not. I'd expect this caps object to be
statically defined, with possibly one instance per-compat if the caps
depend on the HW revision.

>  
> -	if (all_false)
> -		return spi_mem_default_supports_op(mem, op);
> -	else
> -		return spi_mem_dtr_supports_op(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  
>  static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-14 16:24     ` Boris Brezillon
  0 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-14 16:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Tue, 14 Dec 2021 12:41:39 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> This driver can be simplified a little bit by using
> spi_mem_generic_supports_op() instead of the
> spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> inverted to become a dtr boolean, which checks if at least one of the
> operation member uses dtr mode. The idea behind this change is to
> simplify the introduction of the pipelined ECC engine.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/spi/spi-mxic.c | 10 +++-------
>  1 file changed, 3 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> index 485a7f2afb44..5e71aa630504 100644
> --- a/drivers/spi/spi-mxic.c
> +++ b/drivers/spi/spi-mxic.c
> @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
>  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  				     const struct spi_mem_op *op)
>  {
> -	bool all_false;
> +	struct spi_mem_controller_caps caps = {};
>  
>  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
>  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
>  	if (op->addr.nbytes > 7)
>  		return false;
>  
> -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> -		    !op->data.dtr;
> +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;

Are you sure that's what you want to do? spi_mem_controller_caps is
supposed to encode the controller capabilities, not whether the
operation contains a DTR cycle or not. I'd expect this caps object to be
statically defined, with possibly one instance per-compat if the caps
depend on the HW revision.

>  
> -	if (all_false)
> -		return spi_mem_default_supports_op(mem, op);
> -	else
> -		return spi_mem_dtr_supports_op(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  
>  static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 06/13] spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
  2021-12-14 11:41   ` Miquel Raynal
@ 2021-12-14 16:29     ` Boris Brezillon
  -1 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-14 16:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Tue, 14 Dec 2021 12:41:33 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> +	if (!caps->ecc) {
> +		if (op->ecc_en)
> +			return false;
> +	}
> +

Nit:

	if (op->ecc_en && !caps->ecc)
		return false;

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 06/13] spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure
@ 2021-12-14 16:29     ` Boris Brezillon
  0 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-14 16:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Tue, 14 Dec 2021 12:41:33 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> +	if (!caps->ecc) {
> +		if (op->ecc_en)
> +			return false;
> +	}
> +

Nit:

	if (op->ecc_en && !caps->ecc)
		return false;

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
  2021-12-14 11:41   ` Miquel Raynal
@ 2021-12-14 19:53     ` Pratyush Yadav
  -1 siblings, 0 replies; 60+ messages in thread
From: Pratyush Yadav @ 2021-12-14 19:53 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Michael Walle, linux-mtd, Mark Brown, linux-spi, Julien Su,
	Jaime Liao, Thomas Petazzoni, Boris Brezillon, Xiangsheng Hou

Hi Miquel,

On 14/12/21 12:41PM, Miquel Raynal wrote:
> So far we check the support for:
> - regular operations
> - dtr operations
> Soon, we will also need to check the support for ECC operations.
> 
> As the combinatorial will increase exponentially, let's gather all the
> checks in a single generic function which takes a capabilities structure
> as input. This new helper is supposed to be called by the currently
> exported functions instead of repeating a similar implementation.

Nice! I think this is a very good idea.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
>  include/linux/spi/spi-mem.h |  8 ++++++++
>  2 files changed, 33 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> index 37f4443ce9a0..4c6944d7b174 100644
> --- a/drivers/spi/spi-mem.c
> +++ b/drivers/spi/spi-mem.c
> @@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
>  	return true;
>  }
>  
> +static bool spi_mem_generic_supports_op(struct spi_mem *mem,
> +					const struct spi_mem_op *op,
> +					struct spi_mem_controller_caps *caps)
> +{
> +	if (!caps->dtr) {

Nitpick: Please turn the order of the if-else around:

  if (caps->dtr)
    ...
  else
    ...

> +		if (op->cmd.dtr || op->addr.dtr ||
> +		    op->dummy.dtr || op->data.dtr)
> +			return false;
> +
> +		if (op->cmd.nbytes != 1)
> +			return false;
> +	} else {
> +		if (op->cmd.nbytes != 2)
> +			return false;
> +	}
> +
> +	return spi_mem_check_buswidth(mem, op);
> +}
> +
>  bool spi_mem_dtr_supports_op(struct spi_mem *mem,
>  			     const struct spi_mem_op *op)
>  {
> -	if (op->cmd.nbytes != 2)
> -		return false;
> +	struct spi_mem_controller_caps caps = {
> +		.dtr = true,
> +	};
>  
> -	return spi_mem_check_buswidth(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
>  
>  bool spi_mem_default_supports_op(struct spi_mem *mem,
>  				 const struct spi_mem_op *op)

I know this would require a little bit more work from you, but can we 
make spi_mem_default_supports_op() accept the caps as a parameter? And 
drop spi_mem_dtr_supports_op() while we are at it? This would be a lot 
neater I think since we won't have lots of wrapper functions lying 
around.

>  {
> -	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
> -		return false;
> +	struct spi_mem_controller_caps caps = {};
>  
> -	if (op->cmd.nbytes != 1)
> -		return false;
> -
> -	return spi_mem_check_buswidth(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
>  
> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> index 85e2ff7b840d..f365efcfb719 100644
> --- a/include/linux/spi/spi-mem.h
> +++ b/include/linux/spi/spi-mem.h
> @@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
>  	return mem->drvpriv;
>  }
>  
> +/**
> + * struct spi_mem_controller_caps - SPI memory controller capabilities
> + * @dtr: Supports DTR operations
> + */
> +struct spi_mem_controller_caps {
> +	bool dtr;
> +};
> +
>  /**
>   * struct spi_controller_mem_ops - SPI memory operations
>   * @adjust_op_size: shrink the data xfer of an operation to match controller's
> -- 
> 2.27.0
> 

-- 
Regards,
Pratyush Yadav
Texas Instruments Inc.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
@ 2021-12-14 19:53     ` Pratyush Yadav
  0 siblings, 0 replies; 60+ messages in thread
From: Pratyush Yadav @ 2021-12-14 19:53 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Michael Walle, linux-mtd, Mark Brown, linux-spi, Julien Su,
	Jaime Liao, Thomas Petazzoni, Boris Brezillon, Xiangsheng Hou

Hi Miquel,

On 14/12/21 12:41PM, Miquel Raynal wrote:
> So far we check the support for:
> - regular operations
> - dtr operations
> Soon, we will also need to check the support for ECC operations.
> 
> As the combinatorial will increase exponentially, let's gather all the
> checks in a single generic function which takes a capabilities structure
> as input. This new helper is supposed to be called by the currently
> exported functions instead of repeating a similar implementation.

Nice! I think this is a very good idea.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
>  include/linux/spi/spi-mem.h |  8 ++++++++
>  2 files changed, 33 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> index 37f4443ce9a0..4c6944d7b174 100644
> --- a/drivers/spi/spi-mem.c
> +++ b/drivers/spi/spi-mem.c
> @@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
>  	return true;
>  }
>  
> +static bool spi_mem_generic_supports_op(struct spi_mem *mem,
> +					const struct spi_mem_op *op,
> +					struct spi_mem_controller_caps *caps)
> +{
> +	if (!caps->dtr) {

Nitpick: Please turn the order of the if-else around:

  if (caps->dtr)
    ...
  else
    ...

> +		if (op->cmd.dtr || op->addr.dtr ||
> +		    op->dummy.dtr || op->data.dtr)
> +			return false;
> +
> +		if (op->cmd.nbytes != 1)
> +			return false;
> +	} else {
> +		if (op->cmd.nbytes != 2)
> +			return false;
> +	}
> +
> +	return spi_mem_check_buswidth(mem, op);
> +}
> +
>  bool spi_mem_dtr_supports_op(struct spi_mem *mem,
>  			     const struct spi_mem_op *op)
>  {
> -	if (op->cmd.nbytes != 2)
> -		return false;
> +	struct spi_mem_controller_caps caps = {
> +		.dtr = true,
> +	};
>  
> -	return spi_mem_check_buswidth(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
>  
>  bool spi_mem_default_supports_op(struct spi_mem *mem,
>  				 const struct spi_mem_op *op)

I know this would require a little bit more work from you, but can we 
make spi_mem_default_supports_op() accept the caps as a parameter? And 
drop spi_mem_dtr_supports_op() while we are at it? This would be a lot 
neater I think since we won't have lots of wrapper functions lying 
around.

>  {
> -	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
> -		return false;
> +	struct spi_mem_controller_caps caps = {};
>  
> -	if (op->cmd.nbytes != 1)
> -		return false;
> -
> -	return spi_mem_check_buswidth(mem, op);
> +	return spi_mem_generic_supports_op(mem, op, &caps);
>  }
>  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
>  
> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> index 85e2ff7b840d..f365efcfb719 100644
> --- a/include/linux/spi/spi-mem.h
> +++ b/include/linux/spi/spi-mem.h
> @@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
>  	return mem->drvpriv;
>  }
>  
> +/**
> + * struct spi_mem_controller_caps - SPI memory controller capabilities
> + * @dtr: Supports DTR operations
> + */
> +struct spi_mem_controller_caps {
> +	bool dtr;
> +};
> +
>  /**
>   * struct spi_controller_mem_ops - SPI memory operations
>   * @adjust_op_size: shrink the data xfer of an operation to match controller's
> -- 
> 2.27.0
> 

-- 
Regards,
Pratyush Yadav
Texas Instruments Inc.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
  2021-12-14 19:53     ` Pratyush Yadav
@ 2021-12-15 16:11       ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-15 16:11 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Michael Walle, linux-mtd, Mark Brown, linux-spi, Julien Su,
	Jaime Liao, Thomas Petazzoni, Boris Brezillon, Xiangsheng Hou

Hi Pratyush,

p.yadav@ti.com wrote on Wed, 15 Dec 2021 01:23:17 +0530:

> Hi Miquel,
> 
> On 14/12/21 12:41PM, Miquel Raynal wrote:
> > So far we check the support for:
> > - regular operations
> > - dtr operations
> > Soon, we will also need to check the support for ECC operations.
> > 
> > As the combinatorial will increase exponentially, let's gather all the
> > checks in a single generic function which takes a capabilities structure
> > as input. This new helper is supposed to be called by the currently
> > exported functions instead of repeating a similar implementation.  
> 
> Nice! I think this is a very good idea.

Thanks!

> 
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
> >  include/linux/spi/spi-mem.h |  8 ++++++++
> >  2 files changed, 33 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> > index 37f4443ce9a0..4c6944d7b174 100644
> > --- a/drivers/spi/spi-mem.c
> > +++ b/drivers/spi/spi-mem.c
> > @@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
> >  	return true;
> >  }
> >  
> > +static bool spi_mem_generic_supports_op(struct spi_mem *mem,
> > +					const struct spi_mem_op *op,
> > +					struct spi_mem_controller_caps *caps)
> > +{
> > +	if (!caps->dtr) {  
> 
> Nitpick: Please turn the order of the if-else around:
> 
>   if (caps->dtr)
>     ...
>   else
>     ...

Yup

> 
> > +		if (op->cmd.dtr || op->addr.dtr ||
> > +		    op->dummy.dtr || op->data.dtr)
> > +			return false;
> > +
> > +		if (op->cmd.nbytes != 1)
> > +			return false;
> > +	} else {
> > +		if (op->cmd.nbytes != 2)
> > +			return false;
> > +	}
> > +
> > +	return spi_mem_check_buswidth(mem, op);
> > +}
> > +
> >  bool spi_mem_dtr_supports_op(struct spi_mem *mem,
> >  			     const struct spi_mem_op *op)
> >  {
> > -	if (op->cmd.nbytes != 2)
> > -		return false;
> > +	struct spi_mem_controller_caps caps = {
> > +		.dtr = true,
> > +	};
> >  
> > -	return spi_mem_check_buswidth(mem, op);
> > +	return spi_mem_generic_supports_op(mem, op, &caps);
> >  }
> >  EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
> >  
> >  bool spi_mem_default_supports_op(struct spi_mem *mem,
> >  				 const struct spi_mem_op *op)  
> 
> I know this would require a little bit more work from you, but can we 
> make spi_mem_default_supports_op() accept the caps as a parameter? And 
> drop spi_mem_dtr_supports_op() while we are at it? This would be a lot 
> neater I think since we won't have lots of wrapper functions lying 
> around.

Following Boris' review I planned to kill spi_mem_dtr_supports_op(). I
might as well update spi_mem_default_supports_op() so that controllers
can provide their static capacities if any.

> >  {
> > -	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
> > -		return false;
> > +	struct spi_mem_controller_caps caps = {};
> >  
> > -	if (op->cmd.nbytes != 1)
> > -		return false;
> > -
> > -	return spi_mem_check_buswidth(mem, op);
> > +	return spi_mem_generic_supports_op(mem, op, &caps);
> >  }
> >  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
> >  
> > diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> > index 85e2ff7b840d..f365efcfb719 100644
> > --- a/include/linux/spi/spi-mem.h
> > +++ b/include/linux/spi/spi-mem.h
> > @@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
> >  	return mem->drvpriv;
> >  }
> >  
> > +/**
> > + * struct spi_mem_controller_caps - SPI memory controller capabilities
> > + * @dtr: Supports DTR operations
> > + */
> > +struct spi_mem_controller_caps {
> > +	bool dtr;
> > +};
> > +
> >  /**
> >   * struct spi_controller_mem_ops - SPI memory operations
> >   * @adjust_op_size: shrink the data xfer of an operation to match controller's
> > -- 
> > 2.27.0
> >   
> 


Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks
@ 2021-12-15 16:11       ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-15 16:11 UTC (permalink / raw)
  To: Pratyush Yadav
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Michael Walle, linux-mtd, Mark Brown, linux-spi, Julien Su,
	Jaime Liao, Thomas Petazzoni, Boris Brezillon, Xiangsheng Hou

Hi Pratyush,

p.yadav@ti.com wrote on Wed, 15 Dec 2021 01:23:17 +0530:

> Hi Miquel,
> 
> On 14/12/21 12:41PM, Miquel Raynal wrote:
> > So far we check the support for:
> > - regular operations
> > - dtr operations
> > Soon, we will also need to check the support for ECC operations.
> > 
> > As the combinatorial will increase exponentially, let's gather all the
> > checks in a single generic function which takes a capabilities structure
> > as input. This new helper is supposed to be called by the currently
> > exported functions instead of repeating a similar implementation.  
> 
> Nice! I think this is a very good idea.

Thanks!

> 
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/spi/spi-mem.c       | 34 +++++++++++++++++++++++++---------
> >  include/linux/spi/spi-mem.h |  8 ++++++++
> >  2 files changed, 33 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> > index 37f4443ce9a0..4c6944d7b174 100644
> > --- a/drivers/spi/spi-mem.c
> > +++ b/drivers/spi/spi-mem.c
> > @@ -160,26 +160,42 @@ static bool spi_mem_check_buswidth(struct spi_mem *mem,
> >  	return true;
> >  }
> >  
> > +static bool spi_mem_generic_supports_op(struct spi_mem *mem,
> > +					const struct spi_mem_op *op,
> > +					struct spi_mem_controller_caps *caps)
> > +{
> > +	if (!caps->dtr) {  
> 
> Nitpick: Please turn the order of the if-else around:
> 
>   if (caps->dtr)
>     ...
>   else
>     ...

Yup

> 
> > +		if (op->cmd.dtr || op->addr.dtr ||
> > +		    op->dummy.dtr || op->data.dtr)
> > +			return false;
> > +
> > +		if (op->cmd.nbytes != 1)
> > +			return false;
> > +	} else {
> > +		if (op->cmd.nbytes != 2)
> > +			return false;
> > +	}
> > +
> > +	return spi_mem_check_buswidth(mem, op);
> > +}
> > +
> >  bool spi_mem_dtr_supports_op(struct spi_mem *mem,
> >  			     const struct spi_mem_op *op)
> >  {
> > -	if (op->cmd.nbytes != 2)
> > -		return false;
> > +	struct spi_mem_controller_caps caps = {
> > +		.dtr = true,
> > +	};
> >  
> > -	return spi_mem_check_buswidth(mem, op);
> > +	return spi_mem_generic_supports_op(mem, op, &caps);
> >  }
> >  EXPORT_SYMBOL_GPL(spi_mem_dtr_supports_op);
> >  
> >  bool spi_mem_default_supports_op(struct spi_mem *mem,
> >  				 const struct spi_mem_op *op)  
> 
> I know this would require a little bit more work from you, but can we 
> make spi_mem_default_supports_op() accept the caps as a parameter? And 
> drop spi_mem_dtr_supports_op() while we are at it? This would be a lot 
> neater I think since we won't have lots of wrapper functions lying 
> around.

Following Boris' review I planned to kill spi_mem_dtr_supports_op(). I
might as well update spi_mem_default_supports_op() so that controllers
can provide their static capacities if any.

> >  {
> > -	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
> > -		return false;
> > +	struct spi_mem_controller_caps caps = {};
> >  
> > -	if (op->cmd.nbytes != 1)
> > -		return false;
> > -
> > -	return spi_mem_check_buswidth(mem, op);
> > +	return spi_mem_generic_supports_op(mem, op, &caps);
> >  }
> >  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
> >  
> > diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
> > index 85e2ff7b840d..f365efcfb719 100644
> > --- a/include/linux/spi/spi-mem.h
> > +++ b/include/linux/spi/spi-mem.h
> > @@ -220,6 +220,14 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
> >  	return mem->drvpriv;
> >  }
> >  
> > +/**
> > + * struct spi_mem_controller_caps - SPI memory controller capabilities
> > + * @dtr: Supports DTR operations
> > + */
> > +struct spi_mem_controller_caps {
> > +	bool dtr;
> > +};
> > +
> >  /**
> >   * struct spi_controller_mem_ops - SPI memory operations
> >   * @adjust_op_size: shrink the data xfer of an operation to match controller's
> > -- 
> > 2.27.0
> >   
> 


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-14 16:24     ` Boris Brezillon
@ 2021-12-15 17:44       ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-15 17:44 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:

> On Tue, 14 Dec 2021 12:41:39 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > This driver can be simplified a little bit by using
> > spi_mem_generic_supports_op() instead of the
> > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > inverted to become a dtr boolean, which checks if at least one of the
> > operation member uses dtr mode. The idea behind this change is to
> > simplify the introduction of the pipelined ECC engine.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/spi/spi-mxic.c | 10 +++-------
> >  1 file changed, 3 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > index 485a7f2afb44..5e71aa630504 100644
> > --- a/drivers/spi/spi-mxic.c
> > +++ b/drivers/spi/spi-mxic.c
> > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >  				     const struct spi_mem_op *op)
> >  {
> > -	bool all_false;
> > +	struct spi_mem_controller_caps caps = {};
> >  
> >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >  	if (op->addr.nbytes > 7)
> >  		return false;
> >  
> > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > -		    !op->data.dtr;
> > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;  
> 
> Are you sure that's what you want to do? spi_mem_controller_caps is
> supposed to encode the controller capabilities, not whether the
> operation contains a DTR cycle or not. I'd expect this caps object to be
> statically defined, with possibly one instance per-compat if the caps
> depend on the HW revision.

In order to keep the series easy to review I decided to go for the
following approach:
* Introduce the spi_mem_generic_supports_op_helper() which takes a
  capabilities structure. This helper gathers all the checks from
  spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
  two helpers now call the new one with either a NULL pointer in the
  former case, or a structure with the .dtr parameter set to true in
  the latter.
* Change the API of spi_mem_default_supports_op(), this involves
  updating many different drivers so this change does only that in a
  very transparent way, with no functional changes at all. All the
  drivers provide a NULL parameter for the capabilities structure.
* Actually make use of the new parameter of
  spi_mem_default_supports_op() in the drivers Cadence and Macronix,
  which do have DTR support. This kills the spi_mem_dtr_supports_op()
  helper.
* Kill the temporary spi_mem_generic_supports_op() helper by moving
  all the logic back into spi_mem_default_supports_op().

This approach is really straightforward and easily bisectable if
needed. While working on this, I fixed the check we discussed on IRC
about the command parameter when in a DTR operation. I also reverted
the logic in the various checks, as you suggested.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-15 17:44       ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-15 17:44 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:

> On Tue, 14 Dec 2021 12:41:39 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > This driver can be simplified a little bit by using
> > spi_mem_generic_supports_op() instead of the
> > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > inverted to become a dtr boolean, which checks if at least one of the
> > operation member uses dtr mode. The idea behind this change is to
> > simplify the introduction of the pipelined ECC engine.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/spi/spi-mxic.c | 10 +++-------
> >  1 file changed, 3 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > index 485a7f2afb44..5e71aa630504 100644
> > --- a/drivers/spi/spi-mxic.c
> > +++ b/drivers/spi/spi-mxic.c
> > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >  				     const struct spi_mem_op *op)
> >  {
> > -	bool all_false;
> > +	struct spi_mem_controller_caps caps = {};
> >  
> >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> >  	if (op->addr.nbytes > 7)
> >  		return false;
> >  
> > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > -		    !op->data.dtr;
> > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;  
> 
> Are you sure that's what you want to do? spi_mem_controller_caps is
> supposed to encode the controller capabilities, not whether the
> operation contains a DTR cycle or not. I'd expect this caps object to be
> statically defined, with possibly one instance per-compat if the caps
> depend on the HW revision.

In order to keep the series easy to review I decided to go for the
following approach:
* Introduce the spi_mem_generic_supports_op_helper() which takes a
  capabilities structure. This helper gathers all the checks from
  spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
  two helpers now call the new one with either a NULL pointer in the
  former case, or a structure with the .dtr parameter set to true in
  the latter.
* Change the API of spi_mem_default_supports_op(), this involves
  updating many different drivers so this change does only that in a
  very transparent way, with no functional changes at all. All the
  drivers provide a NULL parameter for the capabilities structure.
* Actually make use of the new parameter of
  spi_mem_default_supports_op() in the drivers Cadence and Macronix,
  which do have DTR support. This kills the spi_mem_dtr_supports_op()
  helper.
* Kill the temporary spi_mem_generic_supports_op() helper by moving
  all the logic back into spi_mem_default_supports_op().

This approach is really straightforward and easily bisectable if
needed. While working on this, I fixed the check we discussed on IRC
about the command parameter when in a DTR operation. I also reverted
the logic in the various checks, as you suggested.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 17:44       ` Miquel Raynal
@ 2021-12-15 18:45         ` Boris Brezillon
  -1 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 18:45 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> 
> > On Tue, 14 Dec 2021 12:41:39 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > This driver can be simplified a little bit by using
> > > spi_mem_generic_supports_op() instead of the
> > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > inverted to become a dtr boolean, which checks if at least one of the
> > > operation member uses dtr mode. The idea behind this change is to
> > > simplify the introduction of the pipelined ECC engine.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/spi/spi-mxic.c | 10 +++-------
> > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > index 485a7f2afb44..5e71aa630504 100644
> > > --- a/drivers/spi/spi-mxic.c
> > > +++ b/drivers/spi/spi-mxic.c
> > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  				     const struct spi_mem_op *op)
> > >  {
> > > -	bool all_false;
> > > +	struct spi_mem_controller_caps caps = {};
> > >  
> > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  	if (op->addr.nbytes > 7)
> > >  		return false;
> > >  
> > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > -		    !op->data.dtr;
> > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;    
> > 
> > Are you sure that's what you want to do? spi_mem_controller_caps is
> > supposed to encode the controller capabilities, not whether the
> > operation contains a DTR cycle or not. I'd expect this caps object to be
> > statically defined, with possibly one instance per-compat if the caps
> > depend on the HW revision.  
> 
> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.
> * Change the API of spi_mem_default_supports_op(), this involves
>   updating many different drivers so this change does only that in a
>   very transparent way, with no functional changes at all. All the
>   drivers provide a NULL parameter for the capabilities structure.
> * Actually make use of the new parameter of
>   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
>   which do have DTR support. This kills the spi_mem_dtr_supports_op()
>   helper.
> * Kill the temporary spi_mem_generic_supports_op() helper by moving
>   all the logic back into spi_mem_default_supports_op().
> 
> This approach is really straightforward and easily bisectable if
> needed.

I don't really see the benefit of converting drivers one by one for
such a trivial/mechanical change to be honest. After all, we're talking
about adding a caps argument to spi_mem_default_supports_op() and
making all existing callers pass a caps object that's zero initialized.
I hope we can get this right in one shot...

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-15 18:45         ` Boris Brezillon
  0 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 18:45 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> 
> > On Tue, 14 Dec 2021 12:41:39 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > This driver can be simplified a little bit by using
> > > spi_mem_generic_supports_op() instead of the
> > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > inverted to become a dtr boolean, which checks if at least one of the
> > > operation member uses dtr mode. The idea behind this change is to
> > > simplify the introduction of the pipelined ECC engine.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/spi/spi-mxic.c | 10 +++-------
> > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > index 485a7f2afb44..5e71aa630504 100644
> > > --- a/drivers/spi/spi-mxic.c
> > > +++ b/drivers/spi/spi-mxic.c
> > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  				     const struct spi_mem_op *op)
> > >  {
> > > -	bool all_false;
> > > +	struct spi_mem_controller_caps caps = {};
> > >  
> > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  	if (op->addr.nbytes > 7)
> > >  		return false;
> > >  
> > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > -		    !op->data.dtr;
> > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;    
> > 
> > Are you sure that's what you want to do? spi_mem_controller_caps is
> > supposed to encode the controller capabilities, not whether the
> > operation contains a DTR cycle or not. I'd expect this caps object to be
> > statically defined, with possibly one instance per-compat if the caps
> > depend on the HW revision.  
> 
> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.
> * Change the API of spi_mem_default_supports_op(), this involves
>   updating many different drivers so this change does only that in a
>   very transparent way, with no functional changes at all. All the
>   drivers provide a NULL parameter for the capabilities structure.
> * Actually make use of the new parameter of
>   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
>   which do have DTR support. This kills the spi_mem_dtr_supports_op()
>   helper.
> * Kill the temporary spi_mem_generic_supports_op() helper by moving
>   all the logic back into spi_mem_default_supports_op().
> 
> This approach is really straightforward and easily bisectable if
> needed.

I don't really see the benefit of converting drivers one by one for
such a trivial/mechanical change to be honest. After all, we're talking
about adding a caps argument to spi_mem_default_supports_op() and
making all existing callers pass a caps object that's zero initialized.
I hope we can get this right in one shot...

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 17:44       ` Miquel Raynal
@ 2021-12-15 18:52         ` Boris Brezillon
  -1 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 18:52 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.

Is there a benefit adding an extra NULL check when you could make sure
all callers pass a zero-initialized caps object when they don't support
fancy features like DTR or ECC.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-15 18:52         ` Boris Brezillon
  0 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 18:52 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.

Is there a benefit adding an extra NULL check when you could make sure
all callers pass a zero-initialized caps object when they don't support
fancy features like DTR or ECC.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 17:44       ` Miquel Raynal
@ 2021-12-15 19:05         ` Boris Brezillon
  -1 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 19:05 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> 
> > On Tue, 14 Dec 2021 12:41:39 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > This driver can be simplified a little bit by using
> > > spi_mem_generic_supports_op() instead of the
> > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > inverted to become a dtr boolean, which checks if at least one of the
> > > operation member uses dtr mode. The idea behind this change is to
> > > simplify the introduction of the pipelined ECC engine.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/spi/spi-mxic.c | 10 +++-------
> > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > index 485a7f2afb44..5e71aa630504 100644
> > > --- a/drivers/spi/spi-mxic.c
> > > +++ b/drivers/spi/spi-mxic.c
> > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  				     const struct spi_mem_op *op)
> > >  {
> > > -	bool all_false;
> > > +	struct spi_mem_controller_caps caps = {};
> > >  
> > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  	if (op->addr.nbytes > 7)
> > >  		return false;
> > >  
> > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > -		    !op->data.dtr;
> > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;    
> > 
> > Are you sure that's what you want to do? spi_mem_controller_caps is
> > supposed to encode the controller capabilities, not whether the
> > operation contains a DTR cycle or not. I'd expect this caps object to be
> > statically defined, with possibly one instance per-compat if the caps
> > depend on the HW revision.  
> 
> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.
> * Change the API of spi_mem_default_supports_op(), this involves
>   updating many different drivers so this change does only that in a
>   very transparent way, with no functional changes at all. All the
>   drivers provide a NULL parameter for the capabilities structure.
> * Actually make use of the new parameter of
>   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
>   which do have DTR support. This kills the spi_mem_dtr_supports_op()
>   helper.
> * Kill the temporary spi_mem_generic_supports_op() helper by moving
>   all the logic back into spi_mem_default_supports_op().
> 
> This approach is really straightforward and easily bisectable if
> needed.

There's also a second option that doesn't involve patching existing
users: add a spi_mem_controller_caps to the spi_controller struct, and
check this instance in your spi_mem_default_supports_op()
implementation. Note that the buswidth check done in the generic
helper is already based on caps exposed by the controller
through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).

> While working on this, I fixed the check we discussed on IRC
> about the command parameter when in a DTR operation. I also reverted
> the logic in the various checks, as you suggested.
> 
> Thanks,
> Miquèl


^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-15 19:05         ` Boris Brezillon
  0 siblings, 0 replies; 60+ messages in thread
From: Boris Brezillon @ 2021-12-15 19:05 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

On Wed, 15 Dec 2021 18:44:26 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> 
> > On Tue, 14 Dec 2021 12:41:39 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > This driver can be simplified a little bit by using
> > > spi_mem_generic_supports_op() instead of the
> > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > inverted to become a dtr boolean, which checks if at least one of the
> > > operation member uses dtr mode. The idea behind this change is to
> > > simplify the introduction of the pipelined ECC engine.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/spi/spi-mxic.c | 10 +++-------
> > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > index 485a7f2afb44..5e71aa630504 100644
> > > --- a/drivers/spi/spi-mxic.c
> > > +++ b/drivers/spi/spi-mxic.c
> > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  				     const struct spi_mem_op *op)
> > >  {
> > > -	bool all_false;
> > > +	struct spi_mem_controller_caps caps = {};
> > >  
> > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > >  	if (op->addr.nbytes > 7)
> > >  		return false;
> > >  
> > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > -		    !op->data.dtr;
> > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;    
> > 
> > Are you sure that's what you want to do? spi_mem_controller_caps is
> > supposed to encode the controller capabilities, not whether the
> > operation contains a DTR cycle or not. I'd expect this caps object to be
> > statically defined, with possibly one instance per-compat if the caps
> > depend on the HW revision.  
> 
> In order to keep the series easy to review I decided to go for the
> following approach:
> * Introduce the spi_mem_generic_supports_op_helper() which takes a
>   capabilities structure. This helper gathers all the checks from
>   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
>   two helpers now call the new one with either a NULL pointer in the
>   former case, or a structure with the .dtr parameter set to true in
>   the latter.
> * Change the API of spi_mem_default_supports_op(), this involves
>   updating many different drivers so this change does only that in a
>   very transparent way, with no functional changes at all. All the
>   drivers provide a NULL parameter for the capabilities structure.
> * Actually make use of the new parameter of
>   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
>   which do have DTR support. This kills the spi_mem_dtr_supports_op()
>   helper.
> * Kill the temporary spi_mem_generic_supports_op() helper by moving
>   all the logic back into spi_mem_default_supports_op().
> 
> This approach is really straightforward and easily bisectable if
> needed.

There's also a second option that doesn't involve patching existing
users: add a spi_mem_controller_caps to the spi_controller struct, and
check this instance in your spi_mem_default_supports_op()
implementation. Note that the buswidth check done in the generic
helper is already based on caps exposed by the controller
through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).

> While working on this, I fixed the check we discussed on IRC
> about the command parameter when in a DTR operation. I also reverted
> the logic in the various checks, as you suggested.
> 
> Thanks,
> Miquèl


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 19:05         ` Boris Brezillon
@ 2021-12-15 19:19           ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2021-12-15 19:19 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

[-- Attachment #1: Type: text/plain, Size: 705 bytes --]

On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:

> There's also a second option that doesn't involve patching existing
> users: add a spi_mem_controller_caps to the spi_controller struct, and
> check this instance in your spi_mem_default_supports_op()
> implementation. Note that the buswidth check done in the generic
> helper is already based on caps exposed by the controller
> through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).

This approach is quite nice for things like this - having things as data
rather than code.  The only issue is if any of the caps end up varying
by operation and we need different capabilities but that doesn't look
too likely here I think?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-15 19:19           ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2021-12-15 19:19 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou


[-- Attachment #1.1: Type: text/plain, Size: 705 bytes --]

On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:

> There's also a second option that doesn't involve patching existing
> users: add a spi_mem_controller_caps to the spi_controller struct, and
> check this instance in your spi_mem_default_supports_op()
> implementation. Note that the buswidth check done in the generic
> helper is already based on caps exposed by the controller
> through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).

This approach is quite nice for things like this - having things as data
rather than code.  The only issue is if any of the caps end up varying
by operation and we need different capabilities but that doesn't look
too likely here I think?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 144 bytes --]

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 19:19           ` Mark Brown
@ 2021-12-16  8:07             ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:07 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Boris, Mark,

broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:

> On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> 
> > There's also a second option that doesn't involve patching existing
> > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > check this instance in your spi_mem_default_supports_op()
> > implementation. Note that the buswidth check done in the generic
> > helper is already based on caps exposed by the controller
> > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).  
> 
> This approach is quite nice for things like this - having things as data
> rather than code.  The only issue is if any of the caps end up varying
> by operation and we need different capabilities but that doesn't look
> too likely here I think?

Sure, that's a good idea, I'll look into it.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16  8:07             ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:07 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Boris, Mark,

broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:

> On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> 
> > There's also a second option that doesn't involve patching existing
> > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > check this instance in your spi_mem_default_supports_op()
> > implementation. Note that the buswidth check done in the generic
> > helper is already based on caps exposed by the controller
> > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).  
> 
> This approach is quite nice for things like this - having things as data
> rather than code.  The only issue is if any of the caps end up varying
> by operation and we need different capabilities but that doesn't look
> too likely here I think?

Sure, that's a good idea, I'll look into it.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 18:45         ` Boris Brezillon
@ 2021-12-16  8:11           ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:11 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Wed, 15 Dec 2021 19:45:38 +0100:

> On Wed, 15 Dec 2021 18:44:26 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Hi Boris,
> > 
> > boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> >   
> > > On Tue, 14 Dec 2021 12:41:39 +0100
> > > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >     
> > > > This driver can be simplified a little bit by using
> > > > spi_mem_generic_supports_op() instead of the
> > > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > > inverted to become a dtr boolean, which checks if at least one of the
> > > > operation member uses dtr mode. The idea behind this change is to
> > > > simplify the introduction of the pipelined ECC engine.
> > > > 
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  drivers/spi/spi-mxic.c | 10 +++-------
> > > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > > 
> > > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > > index 485a7f2afb44..5e71aa630504 100644
> > > > --- a/drivers/spi/spi-mxic.c
> > > > +++ b/drivers/spi/spi-mxic.c
> > > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > > >  				     const struct spi_mem_op *op)
> > > >  {
> > > > -	bool all_false;
> > > > +	struct spi_mem_controller_caps caps = {};
> > > >  
> > > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > > >  	if (op->addr.nbytes > 7)
> > > >  		return false;
> > > >  
> > > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > > -		    !op->data.dtr;
> > > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;      
> > > 
> > > Are you sure that's what you want to do? spi_mem_controller_caps is
> > > supposed to encode the controller capabilities, not whether the
> > > operation contains a DTR cycle or not. I'd expect this caps object to be
> > > statically defined, with possibly one instance per-compat if the caps
> > > depend on the HW revision.    
> > 
> > In order to keep the series easy to review I decided to go for the
> > following approach:
> > * Introduce the spi_mem_generic_supports_op_helper() which takes a
> >   capabilities structure. This helper gathers all the checks from
> >   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
> >   two helpers now call the new one with either a NULL pointer in the
> >   former case, or a structure with the .dtr parameter set to true in
> >   the latter.
> > * Change the API of spi_mem_default_supports_op(), this involves
> >   updating many different drivers so this change does only that in a
> >   very transparent way, with no functional changes at all. All the
> >   drivers provide a NULL parameter for the capabilities structure.
> > * Actually make use of the new parameter of
> >   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
> >   which do have DTR support. This kills the spi_mem_dtr_supports_op()
> >   helper.
> > * Kill the temporary spi_mem_generic_supports_op() helper by moving
> >   all the logic back into spi_mem_default_supports_op().
> > 
> > This approach is really straightforward and easily bisectable if
> > needed.  
> 
> I don't really see the benefit of converting drivers one by one for
> such a trivial/mechanical change to be honest. After all, we're talking
> about adding a caps argument to spi_mem_default_supports_op() and
> making all existing callers pass a caps object that's zero initialized.
> I hope we can get this right in one shot...

I'm not converting them one by one, but all in one patch. One by one is
not even an option because it would completely break bisectability.
What I meant is that in a single patch, I was converting all the
drivers using spi_mem_default_supports_op() to pass a third parameter.
In *all* cases, this parameter would be NULL (because I find this
cleaner than providing empty structures for 95% of the drivers). In the
next patch, I would actually convert the users of
spi_mem_dtr_supports_op() to use spi_mem_default_supports_op() by
providing their static capabilities definition.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16  8:11           ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:11 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Wed, 15 Dec 2021 19:45:38 +0100:

> On Wed, 15 Dec 2021 18:44:26 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Hi Boris,
> > 
> > boris.brezillon@collabora.com wrote on Tue, 14 Dec 2021 17:24:10 +0100:
> >   
> > > On Tue, 14 Dec 2021 12:41:39 +0100
> > > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >     
> > > > This driver can be simplified a little bit by using
> > > > spi_mem_generic_supports_op() instead of the
> > > > spi_mem_default/dtr_supports_op() couple. The all_false boolean is
> > > > inverted to become a dtr boolean, which checks if at least one of the
> > > > operation member uses dtr mode. The idea behind this change is to
> > > > simplify the introduction of the pipelined ECC engine.
> > > > 
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  drivers/spi/spi-mxic.c | 10 +++-------
> > > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > > 
> > > > diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
> > > > index 485a7f2afb44..5e71aa630504 100644
> > > > --- a/drivers/spi/spi-mxic.c
> > > > +++ b/drivers/spi/spi-mxic.c
> > > > @@ -452,7 +452,7 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
> > > >  static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > > >  				     const struct spi_mem_op *op)
> > > >  {
> > > > -	bool all_false;
> > > > +	struct spi_mem_controller_caps caps = {};
> > > >  
> > > >  	if (op->data.buswidth > 8 || op->addr.buswidth > 8 ||
> > > >  	    op->dummy.buswidth > 8 || op->cmd.buswidth > 8)
> > > > @@ -465,13 +465,9 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
> > > >  	if (op->addr.nbytes > 7)
> > > >  		return false;
> > > >  
> > > > -	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
> > > > -		    !op->data.dtr;
> > > > +	caps.dtr = op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;      
> > > 
> > > Are you sure that's what you want to do? spi_mem_controller_caps is
> > > supposed to encode the controller capabilities, not whether the
> > > operation contains a DTR cycle or not. I'd expect this caps object to be
> > > statically defined, with possibly one instance per-compat if the caps
> > > depend on the HW revision.    
> > 
> > In order to keep the series easy to review I decided to go for the
> > following approach:
> > * Introduce the spi_mem_generic_supports_op_helper() which takes a
> >   capabilities structure. This helper gathers all the checks from
> >   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
> >   two helpers now call the new one with either a NULL pointer in the
> >   former case, or a structure with the .dtr parameter set to true in
> >   the latter.
> > * Change the API of spi_mem_default_supports_op(), this involves
> >   updating many different drivers so this change does only that in a
> >   very transparent way, with no functional changes at all. All the
> >   drivers provide a NULL parameter for the capabilities structure.
> > * Actually make use of the new parameter of
> >   spi_mem_default_supports_op() in the drivers Cadence and Macronix,
> >   which do have DTR support. This kills the spi_mem_dtr_supports_op()
> >   helper.
> > * Kill the temporary spi_mem_generic_supports_op() helper by moving
> >   all the logic back into spi_mem_default_supports_op().
> > 
> > This approach is really straightforward and easily bisectable if
> > needed.  
> 
> I don't really see the benefit of converting drivers one by one for
> such a trivial/mechanical change to be honest. After all, we're talking
> about adding a caps argument to spi_mem_default_supports_op() and
> making all existing callers pass a caps object that's zero initialized.
> I hope we can get this right in one shot...

I'm not converting them one by one, but all in one patch. One by one is
not even an option because it would completely break bisectability.
What I meant is that in a single patch, I was converting all the
drivers using spi_mem_default_supports_op() to pass a third parameter.
In *all* cases, this parameter would be NULL (because I find this
cleaner than providing empty structures for 95% of the drivers). In the
next patch, I would actually convert the users of
spi_mem_dtr_supports_op() to use spi_mem_default_supports_op() by
providing their static capabilities definition.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 18:52         ` Boris Brezillon
@ 2021-12-16  8:14           ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:14 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Wed, 15 Dec 2021 19:52:19 +0100:

> On Wed, 15 Dec 2021 18:44:26 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > In order to keep the series easy to review I decided to go for the
> > following approach:
> > * Introduce the spi_mem_generic_supports_op_helper() which takes a
> >   capabilities structure. This helper gathers all the checks from
> >   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
> >   two helpers now call the new one with either a NULL pointer in the
> >   former case, or a structure with the .dtr parameter set to true in
> >   the latter.  
> 
> Is there a benefit adding an extra NULL check when you could make sure
> all callers pass a zero-initialized caps object when they don't support
> fancy features like DTR or ECC.

That's exactly my point, I really don't like the creation of 15 empty
and useless structures while we could just have a check. If the
controller provides no capabilities, we assure he has none. I don't
think checking "if (caps && caps->PARAM)" hurts. Anyway, if we go for
the spi_mem controller internal structure approach, we might just not
need those.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16  8:14           ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  8:14 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Richard Weinberger, Vignesh Raghavendra, Tudor Ambarus,
	Pratyush Yadav, Michael Walle, linux-mtd, Mark Brown, linux-spi,
	Julien Su, Jaime Liao, Thomas Petazzoni, Xiangsheng Hou

Hi Boris,

boris.brezillon@collabora.com wrote on Wed, 15 Dec 2021 19:52:19 +0100:

> On Wed, 15 Dec 2021 18:44:26 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > In order to keep the series easy to review I decided to go for the
> > following approach:
> > * Introduce the spi_mem_generic_supports_op_helper() which takes a
> >   capabilities structure. This helper gathers all the checks from
> >   spi_mem_default_supports_op() and spi_mem_dtr_supports_op(). These
> >   two helpers now call the new one with either a NULL pointer in the
> >   former case, or a structure with the .dtr parameter set to true in
> >   the latter.  
> 
> Is there a benefit adding an extra NULL check when you could make sure
> all callers pass a zero-initialized caps object when they don't support
> fancy features like DTR or ECC.

That's exactly my point, I really don't like the creation of 15 empty
and useless structures while we could just have a check. If the
controller provides no capabilities, we assure he has none. I don't
think checking "if (caps && caps->PARAM)" hurts. Anyway, if we go for
the spi_mem controller internal structure approach, we might just not
need those.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-15 19:19           ` Mark Brown
@ 2021-12-16  9:01             ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  9:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Mark,

broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:

> On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> 
> > There's also a second option that doesn't involve patching existing
> > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > check this instance in your spi_mem_default_supports_op()
> > implementation. Note that the buswidth check done in the generic
> > helper is already based on caps exposed by the controller
> > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).  
> 
> This approach is quite nice for things like this - having things as data
> rather than code.  The only issue is if any of the caps end up varying
> by operation and we need different capabilities but that doesn't look
> too likely here I think?

Indeed that was the main point of the original review from Boris, the
capabilities should be fixed on the controller's lifetime. So I believe
we are safe.

I think I am going to propose the following:
	const struct spi_controller_mem_ops *mem_ops;
+	struct spi_controller_mem_caps mem_caps;

As the structure is not supposed to enlarge dramatically in the near
future, I guess it's fine to have it defined statically. Please tell me
if you prefer a *mem_caps pointer.

I'll send a proposal soon.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16  9:01             ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  9:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Mark,

broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:

> On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> 
> > There's also a second option that doesn't involve patching existing
> > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > check this instance in your spi_mem_default_supports_op()
> > implementation. Note that the buswidth check done in the generic
> > helper is already based on caps exposed by the controller
> > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).  
> 
> This approach is quite nice for things like this - having things as data
> rather than code.  The only issue is if any of the caps end up varying
> by operation and we need different capabilities but that doesn't look
> too likely here I think?

Indeed that was the main point of the original review from Boris, the
capabilities should be fixed on the controller's lifetime. So I believe
we are safe.

I think I am going to propose the following:
	const struct spi_controller_mem_ops *mem_ops;
+	struct spi_controller_mem_caps mem_caps;

As the structure is not supposed to enlarge dramatically in the near
future, I guess it's fine to have it defined statically. Please tell me
if you prefer a *mem_caps pointer.

I'll send a proposal soon.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-16  9:01             ` Miquel Raynal
@ 2021-12-16  9:57               ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  9:57 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou


miquel.raynal@bootlin.com wrote on Thu, 16 Dec 2021 10:01:47 +0100:

> Hi Mark,
> 
> broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:
> 
> > On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> >   
> > > There's also a second option that doesn't involve patching existing
> > > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > > check this instance in your spi_mem_default_supports_op()
> > > implementation. Note that the buswidth check done in the generic
> > > helper is already based on caps exposed by the controller
> > > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).    
> > 
> > This approach is quite nice for things like this - having things as data
> > rather than code.  The only issue is if any of the caps end up varying
> > by operation and we need different capabilities but that doesn't look
> > too likely here I think?  
> 
> Indeed that was the main point of the original review from Boris, the
> capabilities should be fixed on the controller's lifetime. So I believe
> we are safe.
> 
> I think I am going to propose the following:
> 	const struct spi_controller_mem_ops *mem_ops;
> +	struct spi_controller_mem_caps mem_caps;
> 
> As the structure is not supposed to enlarge dramatically in the near
> future, I guess it's fine to have it defined statically. Please tell me
> if you prefer a *mem_caps pointer.

Actually as the spi-mem.h header is not included in spi.h, it makes
defining a static mem_caps entry harder. I'll go for another approach.
Maybe putting the capabilities within the spi_controller_mem_ops
structure, as these are highly related.

> I'll send a proposal soon.
> 
> Thanks,
> Miquèl


Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16  9:57               ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16  9:57 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou


miquel.raynal@bootlin.com wrote on Thu, 16 Dec 2021 10:01:47 +0100:

> Hi Mark,
> 
> broonie@kernel.org wrote on Wed, 15 Dec 2021 19:19:11 +0000:
> 
> > On Wed, Dec 15, 2021 at 08:05:48PM +0100, Boris Brezillon wrote:
> >   
> > > There's also a second option that doesn't involve patching existing
> > > users: add a spi_mem_controller_caps to the spi_controller struct, and
> > > check this instance in your spi_mem_default_supports_op()
> > > implementation. Note that the buswidth check done in the generic
> > > helper is already based on caps exposed by the controller
> > > through spi_controller.mode_bits ({RX/TX}_{DUAL,QUAD,OCTAL} bits).    
> > 
> > This approach is quite nice for things like this - having things as data
> > rather than code.  The only issue is if any of the caps end up varying
> > by operation and we need different capabilities but that doesn't look
> > too likely here I think?  
> 
> Indeed that was the main point of the original review from Boris, the
> capabilities should be fixed on the controller's lifetime. So I believe
> we are safe.
> 
> I think I am going to propose the following:
> 	const struct spi_controller_mem_ops *mem_ops;
> +	struct spi_controller_mem_caps mem_caps;
> 
> As the structure is not supposed to enlarge dramatically in the near
> future, I guess it's fine to have it defined statically. Please tell me
> if you prefer a *mem_caps pointer.

Actually as the spi-mem.h header is not included in spi.h, it makes
defining a static mem_caps entry harder. I'll go for another approach.
Maybe putting the capabilities within the spi_controller_mem_ops
structure, as these are highly related.

> I'll send a proposal soon.
> 
> Thanks,
> Miquèl


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-16  9:57               ` Miquel Raynal
@ 2021-12-16 14:04                 ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2021-12-16 14:04 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

[-- Attachment #1: Type: text/plain, Size: 420 bytes --]

On Thu, Dec 16, 2021 at 10:57:39AM +0100, Miquel Raynal wrote:

> Actually as the spi-mem.h header is not included in spi.h, it makes
> defining a static mem_caps entry harder. I'll go for another approach.
> Maybe putting the capabilities within the spi_controller_mem_ops
> structure, as these are highly related.

Yeah, or putting a pointer to a static declaration of the caps in there
rather than the caps directly.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16 14:04                 ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2021-12-16 14:04 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou


[-- Attachment #1.1: Type: text/plain, Size: 420 bytes --]

On Thu, Dec 16, 2021 at 10:57:39AM +0100, Miquel Raynal wrote:

> Actually as the spi-mem.h header is not included in spi.h, it makes
> defining a static mem_caps entry harder. I'll go for another approach.
> Maybe putting the capabilities within the spi_controller_mem_ops
> structure, as these are highly related.

Yeah, or putting a pointer to a static declaration of the caps in there
rather than the caps directly.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 144 bytes --]

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
  2021-12-16 14:04                 ` Mark Brown
@ 2021-12-16 14:27                   ` Miquel Raynal
  -1 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16 14:27 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Mark,

broonie@kernel.org wrote on Thu, 16 Dec 2021 14:04:18 +0000:

> On Thu, Dec 16, 2021 at 10:57:39AM +0100, Miquel Raynal wrote:
> 
> > Actually as the spi-mem.h header is not included in spi.h, it makes
> > defining a static mem_caps entry harder. I'll go for another approach.
> > Maybe putting the capabilities within the spi_controller_mem_ops
> > structure, as these are highly related.  
> 
> Yeah, or putting a pointer to a static declaration of the caps in there
> rather than the caps directly.

Yeah, that's what I ended up doing. Each controller driver supporting
mem-ops must provide a capabilities structure. Drivers without specific
capabilities can just reference the static &spi_mem_no_caps struct
instead of defining their empty one.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op()
@ 2021-12-16 14:27                   ` Miquel Raynal
  0 siblings, 0 replies; 60+ messages in thread
From: Miquel Raynal @ 2021-12-16 14:27 UTC (permalink / raw)
  To: Mark Brown
  Cc: Boris Brezillon, Richard Weinberger, Vignesh Raghavendra,
	Tudor Ambarus, Pratyush Yadav, Michael Walle, linux-mtd,
	linux-spi, Julien Su, Jaime Liao, Thomas Petazzoni,
	Xiangsheng Hou

Hi Mark,

broonie@kernel.org wrote on Thu, 16 Dec 2021 14:04:18 +0000:

> On Thu, Dec 16, 2021 at 10:57:39AM +0100, Miquel Raynal wrote:
> 
> > Actually as the spi-mem.h header is not included in spi.h, it makes
> > defining a static mem_caps entry harder. I'll go for another approach.
> > Maybe putting the capabilities within the spi_controller_mem_ops
> > structure, as these are highly related.  
> 
> Yeah, or putting a pointer to a static declaration of the caps in there
> rather than the caps directly.

Yeah, that's what I ended up doing. Each controller driver supporting
mem-ops must provide a capabilities structure. Drivers without specific
capabilities can just reference the static &spi_mem_no_caps struct
instead of defining their empty one.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 60+ messages in thread

end of thread, other threads:[~2021-12-16 14:28 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-14 11:41 [PATCH v5 00/13] Pipelined ECC engines & Macronix support Miquel Raynal
2021-12-14 11:41 ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 01/13] mtd: nand: ecc: Provide a helper to retrieve a pilelined engine device Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 02/13] mtd: nand: mxic-ecc: Support SPI pipelined mode Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 03/13] mtd: spinand: Delay a little bit the dirmap creation Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 04/13] spi: spi-mem: Create a helper to gather all the supports_op checks Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 19:53   ` Pratyush Yadav
2021-12-14 19:53     ` Pratyush Yadav
2021-12-15 16:11     ` Miquel Raynal
2021-12-15 16:11       ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 05/13] spi: spi-mem: Export the spi_mem_generic_supports_op() helper Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 06/13] spi: spi-mem: Add an ecc_en parameter to the spi_mem_op structure Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 16:29   ` Boris Brezillon
2021-12-14 16:29     ` Boris Brezillon
2021-12-14 11:41 ` [PATCH v5 07/13] mtd: spinand: Create direct mapping descriptors for ECC operations Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 08/13] spi: mxic: Fix the transmit path Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 09/13] spi: mxic: Create a helper to configure the controller before an operation Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 10/13] spi: mxic: Create a helper to ease the start of " Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 11/13] spi: mxic: Add support for direct mapping Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 12/13] spi: mxic: Use spi_mem_generic_supports_op() Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal
2021-12-14 16:24   ` Boris Brezillon
2021-12-14 16:24     ` Boris Brezillon
2021-12-15 17:44     ` Miquel Raynal
2021-12-15 17:44       ` Miquel Raynal
2021-12-15 18:45       ` Boris Brezillon
2021-12-15 18:45         ` Boris Brezillon
2021-12-16  8:11         ` Miquel Raynal
2021-12-16  8:11           ` Miquel Raynal
2021-12-15 18:52       ` Boris Brezillon
2021-12-15 18:52         ` Boris Brezillon
2021-12-16  8:14         ` Miquel Raynal
2021-12-16  8:14           ` Miquel Raynal
2021-12-15 19:05       ` Boris Brezillon
2021-12-15 19:05         ` Boris Brezillon
2021-12-15 19:19         ` Mark Brown
2021-12-15 19:19           ` Mark Brown
2021-12-16  8:07           ` Miquel Raynal
2021-12-16  8:07             ` Miquel Raynal
2021-12-16  9:01           ` Miquel Raynal
2021-12-16  9:01             ` Miquel Raynal
2021-12-16  9:57             ` Miquel Raynal
2021-12-16  9:57               ` Miquel Raynal
2021-12-16 14:04               ` Mark Brown
2021-12-16 14:04                 ` Mark Brown
2021-12-16 14:27                 ` Miquel Raynal
2021-12-16 14:27                   ` Miquel Raynal
2021-12-14 11:41 ` [PATCH v5 13/13] spi: mxic: Add support for pipelined ECC operations Miquel Raynal
2021-12-14 11:41   ` Miquel Raynal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.