[v2] mtd: spi-nor: use spi-mem dirmap API
diff mbox series

Message ID ef173d36-c918-4636-ace6-f6ba82dac672@cogentembedded.com
State New
Headers show
Series
  • [v2] mtd: spi-nor: use spi-mem dirmap API
Related show

Commit Message

Sergei Shtylyov Nov. 7, 2019, 8:49 p.m. UTC
Make use of the spi-mem direct mapping API to let advanced controllers
optimize read/write operations when they support direct mapping.

Based on the original patch by Boris Brezillon <boris.brezillon@bootlin.com>.

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

---
Changes in version 2:
- moved the spi_mem_dirmap_{read|write}() calls from spi_nor_{read|write}() to
  spi_nor_spimem_{read|write}_data().

 drivers/mtd/spi-nor/spi-nor.c |  125 +++++++++++++++++++++++++++++++++---------
 include/linux/mtd/spi-nor.h   |    5 +
 2 files changed, 104 insertions(+), 26 deletions(-)

Comments

Sergei Shtylyov Nov. 7, 2019, 8:56 p.m. UTC | #1
On 11/07/2019 11:49 PM, Sergei Shtylyov wrote:

> Make use of the spi-mem direct mapping API to let advanced controllers
> optimize read/write operations when they support direct mapping.
> 
> Based on the original patch by Boris Brezillon <boris.brezillon@bootlin.com>.
> 
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> 
> ---

   Oope, forgot to mention the base. Was generated again mtd/fixes by mistake,
should still apply to spi-nor/next with only small offsets. 

> Changes in version 2:
> - moved the spi_mem_dirmap_{read|write}() calls from spi_nor_{read|write}() to
>   spi_nor_spimem_{read|write}_data().
> 
>  drivers/mtd/spi-nor/spi-nor.c |  125 +++++++++++++++++++++++++++++++++---------
>  include/linux/mtd/spi-nor.h   |    5 +
>  2 files changed, 104 insertions(+), 26 deletions(-)
[...]

MBR, Sergei
Sergei Shtylyov Nov. 7, 2019, 8:56 p.m. UTC | #2
On 11/07/2019 11:49 PM, Sergei Shtylyov wrote:

> Make use of the spi-mem direct mapping API to let advanced controllers
> optimize read/write operations when they support direct mapping.
> 
> Based on the original patch by Boris Brezillon <boris.brezillon@bootlin.com>.
> 
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> 
> ---

   Oops, forgot to mention the base. Was generated again mtd/fixes by mistake,
should still apply to spi-nor/next with only small offsets. 

> Changes in version 2:
> - moved the spi_mem_dirmap_{read|write}() calls from spi_nor_{read|write}() to
>   spi_nor_spimem_{read|write}_data().
> 
>  drivers/mtd/spi-nor/spi-nor.c |  125 +++++++++++++++++++++++++++++++++---------
>  include/linux/mtd/spi-nor.h   |    5 +
>  2 files changed, 104 insertions(+), 26 deletions(-)
[...]

MBR, Sergei
Boris Brezillon Nov. 9, 2019, 7:35 p.m. UTC | #3
On Thu, 7 Nov 2019 23:49:12 +0300
Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> wrote:

> Make use of the spi-mem direct mapping API to let advanced controllers
> optimize read/write operations when they support direct mapping.
> 
> Based on the original patch by Boris Brezillon <boris.brezillon@bootlin.com>.
> 
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> 
> ---
> Changes in version 2:
> - moved the spi_mem_dirmap_{read|write}() calls from spi_nor_{read|write}() to
>   spi_nor_spimem_{read|write}_data().
> 
>  drivers/mtd/spi-nor/spi-nor.c |  125 +++++++++++++++++++++++++++++++++---------
>  include/linux/mtd/spi-nor.h   |    5 +
>  2 files changed, 104 insertions(+), 26 deletions(-)
> 
> Index: linux/drivers/mtd/spi-nor/spi-nor.c
> ===================================================================
> --- linux.orig/drivers/mtd/spi-nor/spi-nor.c
> +++ linux/drivers/mtd/spi-nor/spi-nor.c
> @@ -305,22 +305,28 @@ static ssize_t spi_nor_spimem_xfer_data(
>  static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,
>  					size_t len, u8 *buf)
>  {
> -	struct spi_mem_op op =
> -		SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
> -			   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
> -			   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
> -			   SPI_MEM_OP_DATA_IN(len, buf, 1));
> -
> -	/* get transfer protocols. */
> -	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
> -	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
> -	op.dummy.buswidth = op.addr.buswidth;
> -	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
> +	if (!nor->dirmap.rdesc) {
> +		struct spi_mem_op op =
> +			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
> +				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
> +				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
> +				   SPI_MEM_OP_DATA_IN(len, buf, 1));
> +
> +		/* get transfer protocols. */
> +		op.cmd.buswidth =
> +			spi_nor_get_protocol_inst_nbits(nor->read_proto);
> +		op.addr.buswidth =
> +			spi_nor_get_protocol_addr_nbits(nor->read_proto);
> +		op.dummy.buswidth = op.addr.buswidth;
> +		op.data.buswidth =
> +			spi_nor_get_protocol_data_nbits(nor->read_proto);
>  
> -	/* convert the dummy cycles to the number of bytes */
> -	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
> +		/* convert the dummy cycles to the number of bytes */
> +		op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
>  
> -	return spi_nor_spimem_xfer_data(nor, &op);
> +		return spi_nor_spimem_xfer_data(nor, &op);
> +	}
> +	return spi_mem_dirmap_read(nor->dirmap.rdesc, from, len, buf);

Can we put the spi_mem_dirmap_read() in the if() branch instead of
having an extra level of indentation for the most complex block.

	if (nor->dirmap.rdesc)
		return spi_mem_dirmap_read(nor->dirmap.rdesc, from,
					   len, buf);

	...

(same comment applies to the write path BTW).

With this addressed, you can add

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

Thanks,

Boris
Sergei Shtylyov Nov. 10, 2019, 7:49 p.m. UTC | #4
Hello!

On 11/09/2019 10:35 PM, Boris Brezillon wrote:

>> Make use of the spi-mem direct mapping API to let advanced controllers
>> optimize read/write operations when they support direct mapping.
>>
>> Based on the original patch by Boris Brezillon <boris.brezillon@bootlin.com>.
>>
>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>>
>> ---
>> Changes in version 2:
>> - moved the spi_mem_dirmap_{read|write}() calls from spi_nor_{read|write}() to
>>   spi_nor_spimem_{read|write}_data().
>>
>>  drivers/mtd/spi-nor/spi-nor.c |  125 +++++++++++++++++++++++++++++++++---------
>>  include/linux/mtd/spi-nor.h   |    5 +
>>  2 files changed, 104 insertions(+), 26 deletions(-)
>>
>> Index: linux/drivers/mtd/spi-nor/spi-nor.c
>> ===================================================================
>> --- linux.orig/drivers/mtd/spi-nor/spi-nor.c
>> +++ linux/drivers/mtd/spi-nor/spi-nor.c
>> @@ -305,22 +305,28 @@ static ssize_t spi_nor_spimem_xfer_data(
>>  static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,
>>  					size_t len, u8 *buf)
>>  {
>> -	struct spi_mem_op op =
>> -		SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
>> -			   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
>> -			   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
>> -			   SPI_MEM_OP_DATA_IN(len, buf, 1));
>> -
>> -	/* get transfer protocols. */
>> -	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
>> -	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
>> -	op.dummy.buswidth = op.addr.buswidth;
>> -	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
>> +	if (!nor->dirmap.rdesc) {
>> +		struct spi_mem_op op =
>> +			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
>> +				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
>> +				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
>> +				   SPI_MEM_OP_DATA_IN(len, buf, 1));
>> +
>> +		/* get transfer protocols. */
>> +		op.cmd.buswidth =
>> +			spi_nor_get_protocol_inst_nbits(nor->read_proto);
>> +		op.addr.buswidth =
>> +			spi_nor_get_protocol_addr_nbits(nor->read_proto);
>> +		op.dummy.buswidth = op.addr.buswidth;
>> +		op.data.buswidth =
>> +			spi_nor_get_protocol_data_nbits(nor->read_proto);
>>  
>> -	/* convert the dummy cycles to the number of bytes */
>> -	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
>> +		/* convert the dummy cycles to the number of bytes */
>> +		op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
>>  
>> -	return spi_nor_spimem_xfer_data(nor, &op);
>> +		return spi_nor_spimem_xfer_data(nor, &op);
>> +	}
>> +	return spi_mem_dirmap_read(nor->dirmap.rdesc, from, len, buf);
> 
> Can we put the spi_mem_dirmap_read() in the if() branch instead of
> having an extra level of indentation for the most complex block.

   Have you noticed a complex variable initializer in that block? Do you want
it to be done on the simple branch as well? 

> 	if (nor->dirmap.rdesc)
> 		return spi_mem_dirmap_read(nor->dirmap.rdesc, from,
> 					   len, buf);
> 
> 	...
> 
> (same comment applies to the write path BTW).
> 
> With this addressed, you can add
> 
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

   Thank you. :-)

> 
> Thanks,
> 
> Boris

MBR, Sergei

Patch
diff mbox series

Index: linux/drivers/mtd/spi-nor/spi-nor.c
===================================================================
--- linux.orig/drivers/mtd/spi-nor/spi-nor.c
+++ linux/drivers/mtd/spi-nor/spi-nor.c
@@ -305,22 +305,28 @@  static ssize_t spi_nor_spimem_xfer_data(
 static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,
 					size_t len, u8 *buf)
 {
-	struct spi_mem_op op =
-		SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
-			   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
-			   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
-			   SPI_MEM_OP_DATA_IN(len, buf, 1));
-
-	/* get transfer protocols. */
-	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
-	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
-	op.dummy.buswidth = op.addr.buswidth;
-	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+	if (!nor->dirmap.rdesc) {
+		struct spi_mem_op op =
+			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
+				   SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
+				   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
+				   SPI_MEM_OP_DATA_IN(len, buf, 1));
+
+		/* get transfer protocols. */
+		op.cmd.buswidth =
+			spi_nor_get_protocol_inst_nbits(nor->read_proto);
+		op.addr.buswidth =
+			spi_nor_get_protocol_addr_nbits(nor->read_proto);
+		op.dummy.buswidth = op.addr.buswidth;
+		op.data.buswidth =
+			spi_nor_get_protocol_data_nbits(nor->read_proto);
 
-	/* convert the dummy cycles to the number of bytes */
-	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+		/* convert the dummy cycles to the number of bytes */
+		op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
 
-	return spi_nor_spimem_xfer_data(nor, &op);
+		return spi_nor_spimem_xfer_data(nor, &op);
+	}
+	return spi_mem_dirmap_read(nor->dirmap.rdesc, from, len, buf);
 }
 
 /**
@@ -354,20 +360,27 @@  static ssize_t spi_nor_read_data(struct
 static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to,
 					 size_t len, const u8 *buf)
 {
-	struct spi_mem_op op =
-		SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
-			   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
-			   SPI_MEM_OP_NO_DUMMY,
-			   SPI_MEM_OP_DATA_OUT(len, buf, 1));
-
-	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
-	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
-	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
+	if (!nor->dirmap.wdesc) {
+		struct spi_mem_op op =
+			SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
+				   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
+				   SPI_MEM_OP_NO_DUMMY,
+				   SPI_MEM_OP_DATA_OUT(len, buf, 1));
 
-	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
-		op.addr.nbytes = 0;
+		op.cmd.buswidth =
+			spi_nor_get_protocol_inst_nbits(nor->write_proto);
+		op.addr.buswidth =
+			spi_nor_get_protocol_addr_nbits(nor->write_proto);
+		op.data.buswidth =
+			spi_nor_get_protocol_data_nbits(nor->write_proto);
+
+		if (nor->program_opcode == SPINOR_OP_AAI_WP &&
+		    nor->sst_write_second)
+			op.addr.nbytes = 0;
 
-	return spi_nor_spimem_xfer_data(nor, &op);
+		return spi_nor_spimem_xfer_data(nor, &op);
+	}
+	return spi_mem_dirmap_write(nor->dirmap.wdesc, to, len, buf);
 }
 
 /**
@@ -4979,6 +4992,58 @@  int spi_nor_scan(struct spi_nor *nor, co
 }
 EXPORT_SYMBOL_GPL(spi_nor_scan);
 
+static int spi_nor_create_read_dirmap(struct spi_nor *nor)
+{
+	struct spi_mem_dirmap_info info = {
+		.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
+				      SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
+				      SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
+				      SPI_MEM_OP_DATA_IN(0, NULL, 1)),
+		.offset = 0,
+		.length = nor->mtd.size,
+	};
+	struct spi_mem_op *op = &info.op_tmpl;
+
+	/* get transfer protocols. */
+	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+	op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+	op->dummy.buswidth = op->addr.buswidth;
+	op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+
+	/* convert the dummy cycles to the number of bytes */
+	op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;
+
+	nor->dirmap.rdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
+						       &info);
+	return PTR_ERR_OR_ZERO(nor->dirmap.rdesc);
+}
+
+static int spi_nor_create_write_dirmap(struct spi_nor *nor)
+{
+	struct spi_mem_dirmap_info info = {
+		.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
+				      SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
+				      SPI_MEM_OP_NO_DUMMY,
+				      SPI_MEM_OP_DATA_OUT(0, NULL, 1)),
+		.offset = 0,
+		.length = nor->mtd.size,
+	};
+	struct spi_mem_op *op = &info.op_tmpl;
+
+	/* get transfer protocols. */
+	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+	op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+	op->dummy.buswidth = op->addr.buswidth;
+	op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
+
+	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
+		op->addr.nbytes = 0;
+
+	nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
+						       &info);
+	return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
+}
+
 static int spi_nor_probe(struct spi_mem *spimem)
 {
 	struct spi_device *spi = spimem->spi;
@@ -5040,6 +5105,14 @@  static int spi_nor_probe(struct spi_mem
 			return -ENOMEM;
 	}
 
+	ret = spi_nor_create_read_dirmap(nor);
+	if (ret)
+		return ret;
+
+	ret = spi_nor_create_write_dirmap(nor);
+	if (ret)
+		return ret;
+
 	return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
 				   data ? data->nr_parts : 0);
 }
Index: linux/include/linux/mtd/spi-nor.h
===================================================================
--- linux.orig/include/linux/mtd/spi-nor.h
+++ linux/include/linux/mtd/spi-nor.h
@@ -602,6 +602,11 @@  struct spi_nor {
 	int (*clear_sr_bp)(struct spi_nor *nor);
 	struct spi_nor_flash_parameter params;
 
+	struct {
+		struct spi_mem_dirmap_desc *rdesc;
+		struct spi_mem_dirmap_desc *wdesc;
+	} dirmap;
+
 	void *priv;
 };