* [PATCH v4 0/2] mtd: spi-nor: use spi-mem dirmap API @ 2020-01-27 20:23 Sergei Shtylyov 2020-01-27 20:28 ` [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() Sergei Shtylyov 2020-01-27 20:29 ` [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov 0 siblings, 2 replies; 8+ messages in thread From: Sergei Shtylyov @ 2020-01-27 20:23 UTC (permalink / raw) To: Tudor Ambarus, Miquel Raynal, Richard Weinberger, Vignesh Raghavendra, linux-mtd Here's a set of 2 patches against the 'spi-nor/next' branch of the MTD 'linux.git' repo. We make use of the spi-mem direct mapping API to let advanced controllers optimize read/write operations when they support direct mapping. Previous versions only had a single patch, in this version a preparatory patch was added. The previous posting had garbage in the subject, so resending with this fixed...) [1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() [2/2] mtd: spi-nor: use spi-mem dirmap API ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() 2020-01-27 20:23 [PATCH v4 0/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov @ 2020-01-27 20:28 ` Sergei Shtylyov 2020-01-28 6:50 ` Boris Brezillon 2020-02-16 22:40 ` Tudor.Ambarus 2020-01-27 20:29 ` [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov 1 sibling, 2 replies; 8+ messages in thread From: Sergei Shtylyov @ 2020-01-27 20:28 UTC (permalink / raw) To: Tudor Ambarus, Miquel Raynal, Richard Weinberger, Vignesh Raghavendra, linux-mtd spi_nor_spimem_xfer_data() being a helper function for the data reads/ writes contains 3 fragments that depend on the data direction; and I'm going to add another one to call the SPI dirmap API... I think this function should be split so that the common fragments are put into 2 functions, spi_nor_spimem_bounce() and spi_nor_spimem_exec_op() called from spi_nor_spimem_{read|write}_data(), and the data direction dependent bits moved back into those read/write functions -- that way we would be able to avoid *goto*s otherwise needed in the next patch adding the SPI dirmap support... Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> --- Changes in version 4: - new patch. drivers/mtd/spi-nor/spi-nor.c | 91 +++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 40 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 @@ -246,55 +246,45 @@ struct flash_info { #define JEDEC_MFR(info) ((info)->id[0]) /** - * spi_nor_spimem_xfer_data() - helper function to read/write data to - * flash's memory region + * spi_nor_spimem_bounce() - check if a bounce buffer is needed for the data + * transfer * @nor: pointer to 'struct spi_nor' * @op: pointer to 'struct spi_mem_op' template for transfer * - * Return: number of bytes transferred on success, -errno otherwise + * If we have to use the bounce buffer, the data field in @op will be updated. + * + * Return: true if the bounce buffer is needed, false if not */ -static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor, - struct spi_mem_op *op) +static bool spi_nor_spimem_bounce(struct spi_nor *nor, struct spi_mem_op *op) { - bool usebouncebuf = false; - void *rdbuf = NULL; - const void *buf; - int ret; - - if (op->data.dir == SPI_MEM_DATA_IN) - buf = op->data.buf.in; - else - buf = op->data.buf.out; - - if (object_is_on_stack(buf) || !virt_addr_valid(buf)) - usebouncebuf = true; - - if (usebouncebuf) { + /* op->data.buf.in occupies the same memory as op->data.buf.out */ + if (object_is_on_stack(op->data.buf.in) || + !virt_addr_valid(op->data.buf.in)) { if (op->data.nbytes > nor->bouncebuf_size) op->data.nbytes = nor->bouncebuf_size; - - if (op->data.dir == SPI_MEM_DATA_IN) { - rdbuf = op->data.buf.in; - op->data.buf.in = nor->bouncebuf; - } else { - op->data.buf.out = nor->bouncebuf; - memcpy(nor->bouncebuf, buf, - op->data.nbytes); - } + op->data.buf.in = nor->bouncebuf; + return true; } - ret = spi_mem_adjust_op_size(nor->spimem, op); - if (ret) - return ret; - - ret = spi_mem_exec_op(nor->spimem, op); - if (ret) - return ret; + return false; +} + +/** + * spi_nor_spimem_exec_op() - execute a memory operation + * @nor: pointer to 'struct spi_nor' + * @op: pointer to 'struct spi_mem_op' template for transfer + * + * Return: 0 on success, -error otherwise. + */ +static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op) +{ + int error; - if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN) - memcpy(rdbuf, nor->bouncebuf, op->data.nbytes); + error = spi_mem_adjust_op_size(nor->spimem, op); + if (error) + return error; - return op->data.nbytes; + return spi_mem_exec_op(nor->spimem, op); } /** @@ -315,6 +305,8 @@ static ssize_t spi_nor_spimem_read_data( 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)); + bool usebouncebuf; + int error; /* get transfer protocols. */ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); @@ -325,7 +317,16 @@ static ssize_t spi_nor_spimem_read_data( /* 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); + usebouncebuf = spi_nor_spimem_bounce(nor, &op); + + error = spi_nor_spimem_exec_op(nor, &op); + if (error) + return error; + + if (usebouncebuf) + memcpy(buf, op.data.buf.in, op.data.nbytes); + + return op.data.nbytes; } /** @@ -364,6 +365,8 @@ static ssize_t spi_nor_spimem_write_data SPI_MEM_OP_ADDR(nor->addr_width, to, 1), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 1)); + bool usebouncebuf; + int error; op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); @@ -372,7 +375,15 @@ static ssize_t spi_nor_spimem_write_data if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op.addr.nbytes = 0; - return spi_nor_spimem_xfer_data(nor, &op); + usebouncebuf = spi_nor_spimem_bounce(nor, &op); + if (usebouncebuf) + memcpy(nor->bouncebuf, buf, op.data.nbytes); + + error = spi_nor_spimem_exec_op(nor, &op); + if (error) + return error; + + return op.data.nbytes; } /** ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() 2020-01-27 20:28 ` [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() Sergei Shtylyov @ 2020-01-28 6:50 ` Boris Brezillon 2020-02-16 22:40 ` Tudor.Ambarus 1 sibling, 0 replies; 8+ messages in thread From: Boris Brezillon @ 2020-01-28 6:50 UTC (permalink / raw) To: Sergei Shtylyov Cc: Richard Weinberger, Miquel Raynal, linux-mtd, Vignesh Raghavendra, Tudor Ambarus On Mon, 27 Jan 2020 23:28:05 +0300 Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> wrote: > spi_nor_spimem_xfer_data() being a helper function for the data reads/ > writes contains 3 fragments that depend on the data direction; and I'm > going to add another one to call the SPI dirmap API... > I think this function should be split so that the common fragments are > put into 2 functions, spi_nor_spimem_bounce() and spi_nor_spimem_exec_op() > called from spi_nor_spimem_{read|write}_data(), and the data direction > dependent bits moved back into those read/write functions -- that way we > would be able to avoid *goto*s otherwise needed in the next patch adding > the SPI dirmap support... > > Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> > > --- > Changes in version 4: > - new patch. > > drivers/mtd/spi-nor/spi-nor.c | 91 +++++++++++++++++++++++------------------- > 1 file changed, 51 insertions(+), 40 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 > @@ -246,55 +246,45 @@ struct flash_info { > #define JEDEC_MFR(info) ((info)->id[0]) > > /** > - * spi_nor_spimem_xfer_data() - helper function to read/write data to > - * flash's memory region > + * spi_nor_spimem_bounce() - check if a bounce buffer is needed for the data > + * transfer > * @nor: pointer to 'struct spi_nor' > * @op: pointer to 'struct spi_mem_op' template for transfer > * > - * Return: number of bytes transferred on success, -errno otherwise > + * If we have to use the bounce buffer, the data field in @op will be updated. > + * > + * Return: true if the bounce buffer is needed, false if not > */ > -static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor, > - struct spi_mem_op *op) > +static bool spi_nor_spimem_bounce(struct spi_nor *nor, struct spi_mem_op *op) > { > - bool usebouncebuf = false; > - void *rdbuf = NULL; > - const void *buf; > - int ret; > - > - if (op->data.dir == SPI_MEM_DATA_IN) > - buf = op->data.buf.in; > - else > - buf = op->data.buf.out; > - > - if (object_is_on_stack(buf) || !virt_addr_valid(buf)) > - usebouncebuf = true; > - > - if (usebouncebuf) { > + /* op->data.buf.in occupies the same memory as op->data.buf.out */ > + if (object_is_on_stack(op->data.buf.in) || > + !virt_addr_valid(op->data.buf.in)) { > if (op->data.nbytes > nor->bouncebuf_size) > op->data.nbytes = nor->bouncebuf_size; > - > - if (op->data.dir == SPI_MEM_DATA_IN) { > - rdbuf = op->data.buf.in; > - op->data.buf.in = nor->bouncebuf; > - } else { > - op->data.buf.out = nor->bouncebuf; > - memcpy(nor->bouncebuf, buf, > - op->data.nbytes); > - } > + op->data.buf.in = nor->bouncebuf; > + return true; > } > > - ret = spi_mem_adjust_op_size(nor->spimem, op); > - if (ret) > - return ret; > - > - ret = spi_mem_exec_op(nor->spimem, op); > - if (ret) > - return ret; > + return false; > +} > + > +/** > + * spi_nor_spimem_exec_op() - execute a memory operation > + * @nor: pointer to 'struct spi_nor' > + * @op: pointer to 'struct spi_mem_op' template for transfer > + * > + * Return: 0 on success, -error otherwise. > + */ > +static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op *op) > +{ > + int error; > > - if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN) > - memcpy(rdbuf, nor->bouncebuf, op->data.nbytes); > + error = spi_mem_adjust_op_size(nor->spimem, op); > + if (error) > + return error; > > - return op->data.nbytes; > + return spi_mem_exec_op(nor->spimem, op); > } > > /** > @@ -315,6 +305,8 @@ static ssize_t spi_nor_spimem_read_data( > 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)); > + bool usebouncebuf; > + int error; > > /* get transfer protocols. */ > op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); > @@ -325,7 +317,16 @@ static ssize_t spi_nor_spimem_read_data( > /* 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); > + usebouncebuf = spi_nor_spimem_bounce(nor, &op); > + > + error = spi_nor_spimem_exec_op(nor, &op); > + if (error) > + return error; > + > + if (usebouncebuf) > + memcpy(buf, op.data.buf.in, op.data.nbytes); > + > + return op.data.nbytes; > } > > /** > @@ -364,6 +365,8 @@ static ssize_t spi_nor_spimem_write_data > SPI_MEM_OP_ADDR(nor->addr_width, to, 1), > SPI_MEM_OP_NO_DUMMY, > SPI_MEM_OP_DATA_OUT(len, buf, 1)); > + bool usebouncebuf; > + int error; > > op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); > op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); > @@ -372,7 +375,15 @@ static ssize_t spi_nor_spimem_write_data > if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) > op.addr.nbytes = 0; > > - return spi_nor_spimem_xfer_data(nor, &op); > + usebouncebuf = spi_nor_spimem_bounce(nor, &op); > + if (usebouncebuf) > + memcpy(nor->bouncebuf, buf, op.data.nbytes); > + > + error = spi_nor_spimem_exec_op(nor, &op); > + if (error) > + return error; > + > + return op.data.nbytes; > } > > /** > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() 2020-01-27 20:28 ` [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() Sergei Shtylyov 2020-01-28 6:50 ` Boris Brezillon @ 2020-02-16 22:40 ` Tudor.Ambarus 2020-02-17 17:47 ` Sergei Shtylyov 1 sibling, 1 reply; 8+ messages in thread From: Tudor.Ambarus @ 2020-02-16 22:40 UTC (permalink / raw) To: sergei.shtylyov; +Cc: richard, linux-mtd, vigneshr, miquel.raynal Hi, Sergei, Looks good. Just a nit below that I can fix it when applying. Let me know if you're ok with the change. On Monday, January 27, 2020 10:28:05 PM EET Sergei Shtylyov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > spi_nor_spimem_xfer_data() being a helper function for the data reads/ > writes contains 3 fragments that depend on the data direction; and I'm > going to add another one to call the SPI dirmap API... > I think this function should be split so that the common fragments are > put into 2 functions, spi_nor_spimem_bounce() and spi_nor_spimem_exec_op() > called from spi_nor_spimem_{read|write}_data(), and the data direction > dependent bits moved back into those read/write functions -- that way we > would be able to avoid *goto*s otherwise needed in the next patch adding > the SPI dirmap support... > > Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> > > --- > Changes in version 4: > - new patch. > > drivers/mtd/spi-nor/spi-nor.c | 91 > +++++++++++++++++++++++------------------- 1 file changed, 51 > insertions(+), 40 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 > @@ -246,55 +246,45 @@ struct flash_info { > #define JEDEC_MFR(info) ((info)->id[0]) > > /** > - * spi_nor_spimem_xfer_data() - helper function to read/write data to > - * flash's memory region > + * spi_nor_spimem_bounce() - check if a bounce buffer is needed for the > data + * transfer > * @nor: pointer to 'struct spi_nor' > * @op: pointer to 'struct spi_mem_op' template for transfer > * > - * Return: number of bytes transferred on success, -errno otherwise > + * If we have to use the bounce buffer, the data field in @op will be > updated. + * > + * Return: true if the bounce buffer is needed, false if not > */ > -static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor, > - struct spi_mem_op *op) > +static bool spi_nor_spimem_bounce(struct spi_nor *nor, struct spi_mem_op > *op) { > - bool usebouncebuf = false; > - void *rdbuf = NULL; > - const void *buf; > - int ret; > - > - if (op->data.dir == SPI_MEM_DATA_IN) > - buf = op->data.buf.in; > - else > - buf = op->data.buf.out; > - > - if (object_is_on_stack(buf) || !virt_addr_valid(buf)) > - usebouncebuf = true; > - > - if (usebouncebuf) { > + /* op->data.buf.in occupies the same memory as op->data.buf.out */ > + if (object_is_on_stack(op->data.buf.in) || > + !virt_addr_valid(op->data.buf.in)) { > if (op->data.nbytes > nor->bouncebuf_size) > op->data.nbytes = nor->bouncebuf_size; > - > - if (op->data.dir == SPI_MEM_DATA_IN) { > - rdbuf = op->data.buf.in; > - op->data.buf.in = nor->bouncebuf; > - } else { > - op->data.buf.out = nor->bouncebuf; > - memcpy(nor->bouncebuf, buf, > - op->data.nbytes); > - } > + op->data.buf.in = nor->bouncebuf; > + return true; > } > > - ret = spi_mem_adjust_op_size(nor->spimem, op); > - if (ret) > - return ret; > - > - ret = spi_mem_exec_op(nor->spimem, op); > - if (ret) > - return ret; > + return false; > +} > + > +/** > + * spi_nor_spimem_exec_op() - execute a memory operation > + * @nor: pointer to 'struct spi_nor' > + * @op: pointer to 'struct spi_mem_op' template for transfer > + * > + * Return: 0 on success, -error otherwise. > + */ > +static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op > *op) +{ > + int error; > > - if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN) > - memcpy(rdbuf, nor->bouncebuf, op->data.nbytes); > + error = spi_mem_adjust_op_size(nor->spimem, op); > + if (error) > + return error; > > - return op->data.nbytes; > + return spi_mem_exec_op(nor->spimem, op); > } > > /** > @@ -315,6 +305,8 @@ static ssize_t spi_nor_spimem_read_data( > 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)); > + bool usebouncebuf; > + int error; > > /* get transfer protocols. */ > op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); > @@ -325,7 +317,16 @@ static ssize_t spi_nor_spimem_read_data( > /* 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); > + usebouncebuf = spi_nor_spimem_bounce(nor, &op); > + > + error = spi_nor_spimem_exec_op(nor, &op); > + if (error) > + return error; > + > + if (usebouncebuf) > + memcpy(buf, op.data.buf.in, op.data.nbytes); > + > + return op.data.nbytes; > } > > /** > @@ -364,6 +365,8 @@ static ssize_t spi_nor_spimem_write_data > SPI_MEM_OP_ADDR(nor->addr_width, to, 1), > SPI_MEM_OP_NO_DUMMY, > SPI_MEM_OP_DATA_OUT(len, buf, 1)); > + bool usebouncebuf; > + int error; > > op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); > op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); @@ > -372,7 +375,15 @@ static ssize_t spi_nor_spimem_write_data > if (nor->program_opcode == SPINOR_OP_AAI_WP && > nor->sst_write_second) op.addr.nbytes = 0; > > - return spi_nor_spimem_xfer_data(nor, &op); > + usebouncebuf = spi_nor_spimem_bounce(nor, &op); > + if (usebouncebuf) > + memcpy(nor->bouncebuf, buf, op.data.nbytes); How about memcpy(nor->bouncebuf, buf, len); instead? spi_nor_spimem_bounce() does not modify op.data.nbytes. Using len is more straight forward than op.data.bytes because the reader doesn't have to verify if length was updated in spi_nor_spimem_bounce() or not. Cheers, ta ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() 2020-02-16 22:40 ` Tudor.Ambarus @ 2020-02-17 17:47 ` Sergei Shtylyov 0 siblings, 0 replies; 8+ messages in thread From: Sergei Shtylyov @ 2020-02-17 17:47 UTC (permalink / raw) To: Tudor.Ambarus; +Cc: richard, linux-mtd, vigneshr, miquel.raynal On 02/17/2020 01:40 AM, Tudor.Ambarus@microchip.com wrote: > Looks good. Just a nit below that I can fix it when applying. Let me know if > you're ok with the change. > > On Monday, January 27, 2020 10:28:05 PM EET Sergei Shtylyov wrote: >> EXTERNAL EMAIL: Do not click links or open attachments unless you know the >> content is safe >> >> spi_nor_spimem_xfer_data() being a helper function for the data reads/ >> writes contains 3 fragments that depend on the data direction; and I'm >> going to add another one to call the SPI dirmap API... >> I think this function should be split so that the common fragments are >> put into 2 functions, spi_nor_spimem_bounce() and spi_nor_spimem_exec_op() >> called from spi_nor_spimem_{read|write}_data(), and the data direction >> dependent bits moved back into those read/write functions -- that way we >> would be able to avoid *goto*s otherwise needed in the next patch adding >> the SPI dirmap support... >> >> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> >> >> --- >> Changes in version 4: >> - new patch. >> >> drivers/mtd/spi-nor/spi-nor.c | 91 >> +++++++++++++++++++++++------------------- 1 file changed, 51 >> insertions(+), 40 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 >> @@ -246,55 +246,45 @@ struct flash_info { >> #define JEDEC_MFR(info) ((info)->id[0]) >> >> /** >> - * spi_nor_spimem_xfer_data() - helper function to read/write data to >> - * flash's memory region >> + * spi_nor_spimem_bounce() - check if a bounce buffer is needed for the >> data + * transfer >> * @nor: pointer to 'struct spi_nor' >> * @op: pointer to 'struct spi_mem_op' template for transfer >> * >> - * Return: number of bytes transferred on success, -errno otherwise >> + * If we have to use the bounce buffer, the data field in @op will be >> updated. + * >> + * Return: true if the bounce buffer is needed, false if not >> */ >> -static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor, >> - struct spi_mem_op *op) >> +static bool spi_nor_spimem_bounce(struct spi_nor *nor, struct spi_mem_op >> *op) { >> - bool usebouncebuf = false; >> - void *rdbuf = NULL; >> - const void *buf; >> - int ret; >> - >> - if (op->data.dir == SPI_MEM_DATA_IN) >> - buf = op->data.buf.in; >> - else >> - buf = op->data.buf.out; >> - >> - if (object_is_on_stack(buf) || !virt_addr_valid(buf)) >> - usebouncebuf = true; >> - >> - if (usebouncebuf) { >> + /* op->data.buf.in occupies the same memory as op->data.buf.out */ >> + if (object_is_on_stack(op->data.buf.in) || >> + !virt_addr_valid(op->data.buf.in)) { >> if (op->data.nbytes > nor->bouncebuf_size) >> op->data.nbytes = nor->bouncebuf_size; >> - >> - if (op->data.dir == SPI_MEM_DATA_IN) { >> - rdbuf = op->data.buf.in; >> - op->data.buf.in = nor->bouncebuf; >> - } else { >> - op->data.buf.out = nor->bouncebuf; >> - memcpy(nor->bouncebuf, buf, >> - op->data.nbytes); >> - } >> + op->data.buf.in = nor->bouncebuf; >> + return true; >> } >> >> - ret = spi_mem_adjust_op_size(nor->spimem, op); >> - if (ret) >> - return ret; >> - >> - ret = spi_mem_exec_op(nor->spimem, op); >> - if (ret) >> - return ret; >> + return false; >> +} >> + >> +/** >> + * spi_nor_spimem_exec_op() - execute a memory operation >> + * @nor: pointer to 'struct spi_nor' >> + * @op: pointer to 'struct spi_mem_op' template for transfer >> + * >> + * Return: 0 on success, -error otherwise. >> + */ >> +static int spi_nor_spimem_exec_op(struct spi_nor *nor, struct spi_mem_op >> *op) +{ >> + int error; >> >> - if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN) >> - memcpy(rdbuf, nor->bouncebuf, op->data.nbytes); >> + error = spi_mem_adjust_op_size(nor->spimem, op); >> + if (error) >> + return error; >> >> - return op->data.nbytes; >> + return spi_mem_exec_op(nor->spimem, op); >> } >> >> /** [...] >> @@ -364,6 +365,8 @@ static ssize_t spi_nor_spimem_write_data >> SPI_MEM_OP_ADDR(nor->addr_width, to, 1), >> SPI_MEM_OP_NO_DUMMY, >> SPI_MEM_OP_DATA_OUT(len, buf, 1)); >> + bool usebouncebuf; >> + int error; >> >> op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); >> op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); @@ >> -372,7 +375,15 @@ static ssize_t spi_nor_spimem_write_data >> if (nor->program_opcode == SPINOR_OP_AAI_WP && >> nor->sst_write_second) op.addr.nbytes = 0; >> >> - return spi_nor_spimem_xfer_data(nor, &op); >> + usebouncebuf = spi_nor_spimem_bounce(nor, &op); >> + if (usebouncebuf) >> + memcpy(nor->bouncebuf, buf, op.data.nbytes); > > How about memcpy(nor->bouncebuf, buf, len); instead? spi_nor_spimem_bounce() changes op.data.nbytes iff the original buffer is larger than the bounce buffer. I don't want to copy the data which I'm unable to write put anyway. > spi_nor_spimem_bounce() does not modify op.data.nbytes. Surely it does! > Using len is more > straight forward than op.data.bytes because the reader doesn't have to verify > if length was updated in spi_nor_spimem_bounce() or not. Sorry, I can't agree with your analysis... > Cheers, > ta MBR, Sergei ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API 2020-01-27 20:23 [PATCH v4 0/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov 2020-01-27 20:28 ` [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() Sergei Shtylyov @ 2020-01-27 20:29 ` Sergei Shtylyov 2020-02-16 23:03 ` Tudor.Ambarus 1 sibling, 1 reply; 8+ messages in thread From: Sergei Shtylyov @ 2020-01-27 20:29 UTC (permalink / raw) To: Tudor Ambarus, Miquel Raynal, Richard Weinberger, Vignesh Raghavendra, linux-mtd 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> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> --- Changes in version 4: - moved the spi_mem_dirmap_{read|write}() calls closer to the ending of spi_nor_{read|write}(), adapting to the chnages caused by the new patch splitting spi_nor_spimem_xfer_data()... Changes in version 3: - simplified the way spi_mem_dirmap_{read|write}() are called; - added Boris' tag. 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 | 97 ++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/spi-nor.h | 5 ++ 2 files changed, 93 insertions(+), 9 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 @@ -306,6 +306,7 @@ static ssize_t spi_nor_spimem_read_data( SPI_MEM_OP_DUMMY(nor->read_dummy, 1), SPI_MEM_OP_DATA_IN(len, buf, 1)); bool usebouncebuf; + ssize_t nbytes; int error; /* get transfer protocols. */ @@ -319,14 +320,23 @@ static ssize_t spi_nor_spimem_read_data( usebouncebuf = spi_nor_spimem_bounce(nor, &op); - error = spi_nor_spimem_exec_op(nor, &op); - if (error) - return error; + if (nor->dirmap.rdesc) { + nbytes = spi_mem_dirmap_read(nor->dirmap.rdesc, op.addr.val, + op.data.nbytes, op.data.buf.in); + if (nbytes < 0) + return nbytes; + } else { + error = spi_nor_spimem_exec_op(nor, &op); + if (error) + return error; + + nbytes = op.data.nbytes; + } if (usebouncebuf) - memcpy(buf, op.data.buf.in, op.data.nbytes); + memcpy(buf, op.data.buf.in, nbytes); - return op.data.nbytes; + return nbytes; } /** @@ -366,6 +376,7 @@ static ssize_t spi_nor_spimem_write_data SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 1)); bool usebouncebuf; + ssize_t nbytes; int error; op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); @@ -379,11 +390,19 @@ static ssize_t spi_nor_spimem_write_data if (usebouncebuf) memcpy(nor->bouncebuf, buf, op.data.nbytes); - error = spi_nor_spimem_exec_op(nor, &op); - if (error) - return error; + if (nor->dirmap.wdesc) { + nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, op.addr.val, + op.data.nbytes, op.data.buf.out); + if (nbytes < 0) + return nbytes; + } else { + error = spi_nor_spimem_exec_op(nor, &op); + if (error) + return error; + nbytes = op.data.nbytes; + } - return op.data.nbytes; + return nbytes; } /** @@ -5270,6 +5289,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; @@ -5331,6 +5402,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 @@ -604,6 +604,11 @@ struct spi_nor { struct spi_nor_flash_parameter params; + struct { + struct spi_mem_dirmap_desc *rdesc; + struct spi_mem_dirmap_desc *wdesc; + } dirmap; + void *priv; }; ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API 2020-01-27 20:29 ` [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov @ 2020-02-16 23:03 ` Tudor.Ambarus 2020-02-17 18:43 ` Sergei Shtylyov 0 siblings, 1 reply; 8+ messages in thread From: Tudor.Ambarus @ 2020-02-16 23:03 UTC (permalink / raw) To: sergei.shtylyov; +Cc: richard, linux-mtd, vigneshr, miquel.raynal Hi, Sergei, Looks good. Few nits below that I can fix when applying. Let me know if you're ok with the changes. On Monday, January 27, 2020 10:29:06 PM EET Sergei Shtylyov wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the > content is safe > > 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> > Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> > > --- > Changes in version 4: > - moved the spi_mem_dirmap_{read|write}() calls closer to the ending of > spi_nor_{read|write}(), adapting to the chnages caused by the new patch > splitting spi_nor_spimem_xfer_data()... > > Changes in version 3: > - simplified the way spi_mem_dirmap_{read|write}() are called; > - added Boris' tag. > > 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 | 97 > ++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/spi-nor.h | > 5 ++ > 2 files changed, 93 insertions(+), 9 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 > @@ -306,6 +306,7 @@ static ssize_t spi_nor_spimem_read_data( > SPI_MEM_OP_DUMMY(nor->read_dummy, 1), > SPI_MEM_OP_DATA_IN(len, buf, 1)); > bool usebouncebuf; > + ssize_t nbytes; > int error; > > /* get transfer protocols. */ > @@ -319,14 +320,23 @@ static ssize_t spi_nor_spimem_read_data( > > usebouncebuf = spi_nor_spimem_bounce(nor, &op); > > - error = spi_nor_spimem_exec_op(nor, &op); > - if (error) > - return error; > + if (nor->dirmap.rdesc) { > + nbytes = spi_mem_dirmap_read(nor->dirmap.rdesc, op.addr.val, op.data.nbytes = spi_mem_dirmap_read() ? This way we can get rid of the local variable nbytes. > + op.data.nbytes, > op.data.buf.in); + if (nbytes < 0) > + return nbytes; > + } else { > + error = spi_nor_spimem_exec_op(nor, &op); > + if (error) > + return error; > + > + nbytes = op.data.nbytes; > + } > > if (usebouncebuf) > - memcpy(buf, op.data.buf.in, op.data.nbytes); > + memcpy(buf, op.data.buf.in, nbytes); > > - return op.data.nbytes; > + return nbytes; > } > > /** > @@ -366,6 +376,7 @@ static ssize_t spi_nor_spimem_write_data > SPI_MEM_OP_NO_DUMMY, > SPI_MEM_OP_DATA_OUT(len, buf, 1)); > bool usebouncebuf; > + ssize_t nbytes; > int error; > > op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); > @@ -379,11 +390,19 @@ static ssize_t spi_nor_spimem_write_data > if (usebouncebuf) > memcpy(nor->bouncebuf, buf, op.data.nbytes); > > - error = spi_nor_spimem_exec_op(nor, &op); > - if (error) > - return error; > + if (nor->dirmap.wdesc) { > + nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, > op.addr.val, + op.data.nbytes, I'll align this to "(" op.data.nbytes = spi_mem_dirmap_write() ? This way we can get rid of the local variable nbytes. > op.data.buf.out); + if (nbytes < 0) > + return nbytes; you already return nbytes below, we can drop this check. > + } else { > + error = spi_nor_spimem_exec_op(nor, &op); > + if (error) > + return error; > + nbytes = op.data.nbytes; > + } > > - return op.data.nbytes; > + return nbytes; > } Cheers, ta ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API 2020-02-16 23:03 ` Tudor.Ambarus @ 2020-02-17 18:43 ` Sergei Shtylyov 0 siblings, 0 replies; 8+ messages in thread From: Sergei Shtylyov @ 2020-02-17 18:43 UTC (permalink / raw) To: Tudor.Ambarus; +Cc: richard, linux-mtd, vigneshr, miquel.raynal On 02/17/2020 02:03 AM, Tudor.Ambarus@microchip.com wrote: > Looks good. Few nits below that I can fix when applying. Let me know if > you're ok with the changes. > > On Monday, January 27, 2020 10:29:06 PM EET Sergei Shtylyov wrote: >> EXTERNAL EMAIL: Do not click links or open attachments unless you know the >> content is safe >> >> 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> >> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> >> >> --- >> Changes in version 4: >> - moved the spi_mem_dirmap_{read|write}() calls closer to the ending of >> spi_nor_{read|write}(), adapting to the chnages caused by the new patch >> splitting spi_nor_spimem_xfer_data()... >> >> Changes in version 3: >> - simplified the way spi_mem_dirmap_{read|write}() are called; >> - added Boris' tag. >> >> 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 | 97 >> ++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/spi-nor.h | >> 5 ++ >> 2 files changed, 93 insertions(+), 9 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 [...] >> @@ -319,14 +320,23 @@ static ssize_t spi_nor_spimem_read_data( >> >> usebouncebuf = spi_nor_spimem_bounce(nor, &op); >> >> - error = spi_nor_spimem_exec_op(nor, &op); >> - if (error) >> - return error; >> + if (nor->dirmap.rdesc) { >> + nbytes = spi_mem_dirmap_read(nor->dirmap.rdesc, op.addr.val, > > op.data.nbytes = spi_mem_dirmap_read() ? op.data.nbytes is *unsigned int*, spi_mem_dirmap_read() returns ssize_t. > This way we can get rid of the local variable nbytes. op.data.nbytes can't carry the error codes, not even supposed to be of a signed type... [...] >> @@ -379,11 +390,19 @@ static ssize_t spi_nor_spimem_write_data >> if (usebouncebuf) >> memcpy(nor->bouncebuf, buf, op.data.nbytes); >> >> - error = spi_nor_spimem_exec_op(nor, &op); >> - if (error) >> - return error; >> + if (nor->dirmap.wdesc) { >> + nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, >> op.addr.val, + op.data.nbytes, > I'll align this to "(" Sorry about missing that. Copy&paste from the read function played its role here... > op.data.nbytes = spi_mem_dirmap_write() ? Same comments as in the read function... > This way we can get rid of the local variable nbytes. > >> op.data.buf.out); + if (nbytes < 0) >> + return nbytes; > > you already return nbytes below, we can drop this check. Yeah, sorry about that! We've already copied from the bounce buffer >> + } else { >> + error = spi_nor_spimem_exec_op(nor, &op); >> + if (error) >> + return error; >> + nbytes = op.data.nbytes; >> + } >> >> - return op.data.nbytes; >> + return nbytes; >> } > > Cheers, > ta MBR, Sergei ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-02-17 18:44 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-01-27 20:23 [PATCH v4 0/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov 2020-01-27 20:28 ` [PATCH v4 1/2] mtd: spi-nor: split spi_nor_spimem_xfer_data() Sergei Shtylyov 2020-01-28 6:50 ` Boris Brezillon 2020-02-16 22:40 ` Tudor.Ambarus 2020-02-17 17:47 ` Sergei Shtylyov 2020-01-27 20:29 ` [PATCH v4 2/2] mtd: spi-nor: use spi-mem dirmap API Sergei Shtylyov 2020-02-16 23:03 ` Tudor.Ambarus 2020-02-17 18:43 ` Sergei Shtylyov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).