Message ID | 002acfc3-39d7-68e7-aa00-fbb449c3bc71@cogentembedded.com |
---|---|
State | Superseded |
Delegated to: | Ambarus Tudor |
Headers | show |
Series | mtd: spi-nor: use spi-mem dirmap API | expand |
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/
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
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
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; } /**
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(-)