spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Subsystems (3)
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to spi_mem_exec_op() directly.
---
v2:
- Replaces patch "spi: spi-mem: Add optional half-duplex SPI transfer mode" from first patchset version
- No compile-time option but the default to use 2 separate SPI messages to transfer the command and data
drivers/spi/spi-mem.c | 74 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 35 deletions(-)
drivers/spi/spi-mem.c +39 -35
@@ -15,6 +15,8 @@#include <spi-mem.h> #endif +#define OP_BUFFER_SIZE_MAX 16/* Max size for cmd + addr + dummy */ +#ifndef __UBOOT__/** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
@@ -200,8 +202,12 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)bool tx_data = op->data.nbytes && (op->data.dir ==SPI_MEM_DATA_OUT );struct udevice *bus = slave->dev->parent;struct dm_spi_ops *ops =spi_get_ops (bus); -unsigned int xfer_len, pos =0 ; -u8 *tx_buf, *rx_buf =NULL ; +unsigned int pos =0 ; +const u8 *tx_buf; +u8 *rx_buf; +u8 op_buf[OP_BUFFER_SIZE_MAX ]; +int op_len; +u32 flag;int ret;int i;
@@ -330,67 +336,65 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)return -ENOTSUPP ; } - xfer_len =sizeof (op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes + op->data.nbytes; + tx_buf = op->data.buf.out; + rx_buf = op->data.buf.in; -/* -* Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so -* we're guaranteed that this buffer is DMA-able, as required by the -* SPI layer. -*/ - tx_buf =kzalloc (xfer_len,GFP_KERNEL ); -if (!tx_buf) -return -ENOMEM ; - -if (rx_data) { - rx_buf =kzalloc (xfer_len,GFP_KERNEL ); -if (!rx_buf) -return -ENOMEM ; + op_len =sizeof (op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; +if (op_len >OP_BUFFER_SIZE_MAX ) { +printf ("Length for cmd+addr+dummy too big (%d)\n" , op_len); +return -EIO ; } +memset (op_buf,0x00 , op_len); ret =spi_claim_bus (slave);if (ret <0 )return ret; - tx_buf[pos++] = op->cmd.opcode; + op_buf[pos++] = op->cmd.opcode;if (op->addr.nbytes) {for (i =0 ; i < op->addr.nbytes; i++) - tx_buf[pos + i] = op->addr.val >> - (8 * (op->addr.nbytes - i -1 )); + op_buf[pos + i] = op->addr.val >> + (8 * (op->addr.nbytes - i -1 )); pos += op->addr.nbytes; } -if (op->dummy.nbytes) { -memset (tx_buf + pos,0xff , op->dummy.nbytes); - pos += op->dummy.nbytes; +if (op->dummy.nbytes) +memset (op_buf + pos,0xff , op->dummy.nbytes); + +/* 1st transfer: opcode + address + dummy cycles */ + flag =SPI_XFER_BEGIN ; +/* Make sure to set END bit if no tx or rx data messages follow */ +if (!tx_data && !rx_data) + flag |=SPI_XFER_END ; + ret =spi_xfer (slave, op_len *8 , op_buf,NULL , flag); + +if (tx_data) { +/* 2nd transfer a: tx data path */ + ret =spi_xfer (slave, op->data.nbytes *8 , tx_buf,NULL , +SPI_XFER_END ); } -if (tx_data) -memcpy (tx_buf + pos, op->data.buf.out, op->data.nbytes); +if (rx_data) { +/* 2nd transfer b: rx data path */ + ret =spi_xfer (slave, op->data.nbytes *8 ,NULL , rx_buf, +SPI_XFER_END ); + } - ret =spi_xfer (slave, xfer_len *8 , tx_buf, rx_buf, -SPI_XFER_BEGIN |SPI_XFER_END );spi_release_bus (slave);for (i =0 ; i < pos; i++) -debug ("%02x " , tx_buf[i]); +debug ("%02x " , op_buf[i]);debug ("| [%dB %s] " , tx_data || rx_data ? op->data.nbytes :0 , tx_data || rx_data ? (tx_data ?"out" :"in" ) :"-" ); -for (; i < xfer_len; i++) +for (i =0 ; i < op->data.nbytes; i++)debug ("%02x " , tx_data ? tx_buf[i] : rx_buf[i]);debug ("[ret %d]\n" , ret);if (ret <0 )return ret; - -if (rx_data) -memcpy (op->data.buf.in, rx_buf + pos, op->data.nbytes); - -kfree (tx_buf); -kfree (rx_buf);#endif /* __UBOOT__ */ return 0 ;
Signature · 1 line
2.18.0
PATCH v2 2/4 cmd: mtd: Don't abort erase operation when a bad block is detected
It was noticed, that the erase command (mtd erase spi-nand0) aborts upon the first bad block. With this change, bad blocks are now skipped and the erase operation will continue.
---
v2:
- Use an U-Boot "mtd" command specific option to skip the bad block upon erase so that other MTD users are not affected by this change
cmd/mtd.c | 1 + drivers/mtd/nand/core.c | 6 ++++++ include/linux/mtd/mtd.h | 1 + 3 files changed, 8 insertions(+)
cmd/mtd.c +1 -0
@@ -359,6 +359,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) erase_op.addr = off; erase_op.len = len; erase_op.scrub = scrub; + erase_op.skipbad = true; ret =mtd_erase (mtd, &erase_op); }else {
drivers/mtd/nand/core.c +6 -0
@@ -163,6 +163,12 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)while (nanddev_pos_cmp (&pos, &last) <=0 ) { ret =nanddev_erase (nand, &pos);if (ret) { +/* U-Boot special: Allow the users to skip bad blocks */ +if ((ret == -EIO ) && einfo->skipbad) { +nanddev_pos_next_eraseblock (nand, &pos); +continue ; + } + einfo->fail_addr =nanddev_pos_to_offs (nand, &pos);return ret;
include/linux/mtd/mtd.h +1 -0
@@ -53,6 +53,7 @@ struct erase_info {u_char state;struct erase_info *next;int scrub; +bool skipbad; };struct mtd_erase_region_info {
Signature · 1 line
2.18.0
PATCH v2 2/4 cmd: mtd: Don't abort erase operation when a bad block is detected
Quoted 35 lines · On Tue, 7 Aug 2018 14:16:53 +0200 Stefan Roese <[email protected]> wrote:
It was noticed, that the erase command (mtd erase spi-nand0) aborts upon the first bad block. With this change, bad blocks are now skipped and the erase operation will continue.
Signed-off-by Stefan Roese <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>---
v2:
- Use an U-Boot "mtd" command specific option to skip the bad block upon erase so that other MTD users are not affected by this changecmd/mtd.c | 1 + drivers/mtd/nand/core.c | 6 ++++++ include/linux/mtd/mtd.h | 1 + 3 files changed, 8 insertions(+)cmd/mtd.c +1
-0@@ -359,6 +359,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) erase_op.addr = off; erase_op.len = len; erase_op.scrub = scrub; + erase_op.skipbad = true; ret =mtd_erase (mtd, &erase_op); }else {drivers/mtd/nand/core.c +0
-0
drivers/mtd/nand/core.c int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo) · line 171
Quoted 9 lines
drivers/mtd/nand/core.c +6
-0@@ -163,6 +163,12 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)while (nanddev_pos_cmp (&pos, &last) <=0 ) { ret =nanddev_erase (nand, &pos);if (ret) { +/* U-Boot special: Allow the users to skip bad blocks */ +if ((ret == -EIO ) && einfo->skipbad) { +nanddev_pos_next_eraseblock (nand, &pos); +continue ; + } +
If you choose this approach you'll have to patch rawnand and onenand code to do the same (maybe others too), because we want mtd erase to work the same way on all MTD devices.
To be honest, I'd prefer to see that handled in cmd/mtd.c. If you don't like the idea of erasing one block at a time, you can always check the ->fail_addr info when mtd_erase() returns an error, and start over from ->fail_addr + mtd->erasesize.
Quoted 15 lines
drivers/mtd/nand/core.c +0
-0einfo->fail_addr =nanddev_pos_to_offs (nand, &pos);return ret;include/linux/mtd/mtd.h +1
-0@@ -53,6 +53,7 @@ struct erase_info {u_char state;struct erase_info *next;int scrub; +bool skipbad; };struct mtd_erase_region_info {
PATCH v2 3/4 cmd: mtd: Don't use with negative return codes for shell commands
In reply to Stefan RoeseWhen negative return codes are used in commands (do_foo()), the shell prints these messages:
exit not allowed from main input shell.
Change the return codes in the new mtd commands to use only positive values and these annoying warnings are gone.
---
v2:
- Use CMD_RET_FAILURE as return value as suggested by Boris
cmd/mtd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
cmd/mtd.c +10 -8
@@ -188,7 +188,7 @@ static int do_mtd_list(void)if (!dev_nb) {printf ("No MTD device found\n" ); -return -EINVAL ; +return CMD_RET_FAILURE ; }return 0 ;
@@ -269,13 +269,13 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (mtd_is_aligned_with_min_io_size (mtd, off)) {printf ("Offset not aligned with a page (0x%x)\n" , mtd->writesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (mtd_is_aligned_with_min_io_size (mtd, len)) {printf ("Size not a multiple of a page (0x%x)\n" , mtd->writesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (dump)
@@ -285,7 +285,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (!buf) {printf ("Could not map/allocate the user buffer\n" ); -return -ENOMEM ; +return CMD_RET_FAILURE ; } printf("%s %lldB (%d page(s)) at offset 0x%08llx%s%s\n",
@@ -306,7 +306,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (ret) {printf ("%s on %s failed with error %d\n" , read ?"Read" :"Write" , mtd->name, ret); -return ret; +return CMD_RET_FAILURE ; }if (dump) {
@@ -346,13 +346,13 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (mtd_is_aligned_with_block_size (mtd, off)) {printf ("Offset not aligned with a block (0x%x)\n" , mtd->erasesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (mtd_is_aligned_with_block_size (mtd, len)) {printf ("Size not a multiple of a block (0x%x)\n" , mtd->erasesize); -return -EINVAL ; +return CMD_RET_FAILURE ; } erase_op.mtd = mtd;
@@ -366,7 +366,9 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_USAGE ; } -return ret; +if (ret) +return CMD_RET_FAILURE ; +return 0 ; } static char mtd_help_text[] =
Signature · 1 line
2.18.0
PATCH v2 3/4 cmd: mtd: Don't use with negative return codes for shell commands
Quoted 5 lines · On Tue, 7 Aug 2018 14:16:54 +0200 Stefan Roese <[email protected]> wrote:
When negative return codes are used in commands (
do_foo()), the shell prints these messages:exit not allowed from main input shell.
Quoted 7 lines
Change the return codes in the new mtd commands to use only positive values and these annoying warnings are gone.
Signed-off-by Stefan Roese <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>
Quoted 81 lines
---
v2:
- UseCMD_RET_FAILUREas return value as suggested by Boriscmd/mtd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)cmd/mtd.c +10
-8@@ -188,7 +188,7 @@ static int do_mtd_list(void)if (!dev_nb) {printf ("No MTD device found\n" ); -return -EINVAL ; +return CMD_RET_FAILURE ; }return 0 ;@@ -269,13 +269,13 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (mtd_is_aligned_with_min_io_size (mtd, off)) {printf ("Offset not aligned with a page (0x%x)\n" , mtd->writesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (mtd_is_aligned_with_min_io_size (mtd, len)) {printf ("Size not a multiple of a page (0x%x)\n" , mtd->writesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (dump)@@ -285,7 +285,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (!buf) {printf ("Could not map/allocate the user buffer\n" ); -return -ENOMEM ; +return CMD_RET_FAILURE ; } printf("%s %lldB (%d page(s)) at offset 0x%08llx%s%s\n",@@ -306,7 +306,7 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (ret) {printf ("%s on %s failed with error %d\n" , read ?"Read" :"Write" , mtd->name, ret); -return ret; +return CMD_RET_FAILURE ; }if (dump) {@@ -346,13 +346,13 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])if (mtd_is_aligned_with_block_size (mtd, off)) {printf ("Offset not aligned with a block (0x%x)\n" , mtd->erasesize); -return -EINVAL ; +return CMD_RET_FAILURE ; }if (mtd_is_aligned_with_block_size (mtd, len)) {printf ("Size not a multiple of a block (0x%x)\n" , mtd->erasesize); -return -EINVAL ; +return CMD_RET_FAILURE ; } erase_op.mtd = mtd;@@ -366,7 +366,9 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_USAGE ; } -return ret; +if (ret) +return CMD_RET_FAILURE ; +return 0 ; } static char mtd_help_text[] =
PATCH v2 4/4 cmd: mtd: Add info text to mtd erase subcommand
In reply to Stefan RoeseAdding this info helps seeing, what really is being erased - especially if no arguments are passed for offset and size. Now this is the output:
=> mtd erase spi-nand0
Erasing 0x00000000 ... 0x07ffffff (1024 eraseblock(s))
nand: attempt to erase a bad/reserved block @6000000
nand: attempt to erase a bad/reserved block @7fe0000
---
v2:
- Print number of eraseblocks instead of pages as suggested by Boris
cmd/mtd.c | 3 +++ 1 file changed, 3 insertions(+)
cmd/mtd.c +3 -0
@@ -355,6 +355,9 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_FAILURE ; } +printf ("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n" , + off, off + len -1 ,mtd_div_by_eb (len, mtd)); + erase_op.mtd = mtd; erase_op.addr = off; erase_op.len = len;
Signature · 1 line
2.18.0
PATCH v2 4/4 cmd: mtd: Add info text to mtd erase subcommand
Hi Stefan,
Quoted 25 lines · On Tue, 7 Aug 2018 14:16:55 +0200 Stefan Roese <[email protected]> wrote:
Adding this info helps seeing, what really is being erased - especially if no arguments are passed for offset and size. Now this is the output:
=> mtd erase spi-nand0
Erasing0x00000000...0x07ffffff(1024 eraseblock(s))
nand: attempt to erase a bad/reserved block @6000000
nand: attempt to erase a bad/reserved block @7fe0000Signed-off-by Stefan Roese <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>---
v2:
- Print number of eraseblocks instead of pages as suggested by Boriscmd/mtd.c | 3 +++ 1 file changed, 3 insertions(+)cmd/mtd.c +0
-0
cmd/mtd.c static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 363
Quoted 9 lines
cmd/mtd.c +3
-0@@ -355,6 +355,9 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_FAILURE ; } +printf ("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n" , + off, off + len -1 ,mtd_div_by_eb (len, mtd)); + erase_op.mtd = mtd; erase_op.addr = off; erase_op.len = len;
Hm, you might want to tell the user where the request failed (when it failed).
Also, maybe we should squash your changes in Miquel's commits since the series has not been merged yet. Unless you'd like to keep them separate.
Regards,
Boris
PATCH v2 4/4 cmd: mtd: Add info text to mtd erase subcommand
Hi Boris,
Quoted 43 lines · Boris Brezillon
Hi Stefan,
Quoted 25 lines · On Tue, 7 Aug 2018 14:16:55 +0200 Stefan Roese <[email protected]> wrote:
Adding this info helps seeing, what really is being erased - especially if no arguments are passed for offset and size. Now this is the output:
=> mtd erase spi-nand0
Erasing0x00000000...0x07ffffff(1024 eraseblock(s))
nand: attempt to erase a bad/reserved block @6000000
nand: attempt to erase a bad/reserved block @7fe0000Signed-off-by Stefan Roese <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>---
v2:
- Print number of eraseblocks instead of pages as suggested by Boriscmd/mtd.c | 3 +++ 1 file changed, 3 insertions(+)cmd/mtd.c +0
-0cmd/mtd.c static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 363
Quoted 9 lines
cmd/mtd.c +3
-0@@ -355,6 +355,9 @@ static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])return CMD_RET_FAILURE ; } +printf ("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n" , + off, off + len -1 ,mtd_div_by_eb (len, mtd)); + erase_op.mtd = mtd; erase_op.addr = off; erase_op.len = len;Hm, you might want to tell the user where the request failed (when it failed).
Quoted 3 lines
Also, maybe we should squash your changes in Miquel's commits since the series has not been merged yet. Unless you'd like to keep them separate.
Squashing them would be just fine with me. I won't find much time today to rework the remaining patches but will do so most likely tomorrow. Please stay tuned and many thanks for the really helpful reviews.
Thanks,
Stefan
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
In reply to Stefan RoeseQuoted 4 lines · On Tue, 7 Aug 2018 14:16:52 +0200 Stefan Roese <[email protected]> wrote:
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>
Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Quoted 24 lines
---
v2:
- Replaces patch "spi: spi-mem: Add optional half-duplex SPI transfer mode" from first patchset version
- No compile-time option but the default to use 2 separate SPI messages to transfer the command and datadrivers/spi/spi-mem.c | 74 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 35 deletions(-)drivers/spi/spi-mem.c +2
-0@@ -15,6 +15,8 @@#include <spi-mem.h> #endif +#define OP_BUFFER_SIZE_MAX 16/* Max size for cmd + addr + dummy */ +#ifndef __UBOOT__/** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 208
Quoted 9 lines
drivers/spi/spi-mem.c +4
-2@@ -200,8 +202,12 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)bool tx_data = op->data.nbytes && (op->data.dir ==SPI_MEM_DATA_OUT );struct udevice *bus = slave->dev->parent;struct dm_spi_ops *ops =spi_get_ops (bus); -unsigned int xfer_len, pos =0 ; -u8 *tx_buf, *rx_buf =NULL ; +unsigned int pos =0 ; +const u8 *tx_buf; +u8 *rx_buf; +u8 op_buf[OP_BUFFER_SIZE_MAX ];
u8 op_buf[OP_BUFFER_SIZE_MAX] = { };and you can get rid of the memset(0) in the code.
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 340
Quoted 13 lines
drivers/spi/spi-mem.c +4
-2+int op_len; +u32 flag;int ret;int i;@@ -330,67 +336,65 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)return -ENOTSUPP ; } - xfer_len =sizeof (op->cmd.opcode) + op->addr.nbytes + - op->dummy.nbytes + op->data.nbytes; + tx_buf = op->data.buf.out; + rx_buf = op->data.buf.in;
I think you can get rid of rx/tx_data and just keep rx/tx_buf. Initialize them to NULL at declaration time and then do:
if (op->data.nbytes) {
if (op->data->dir == SPI_MEM_DATA_IN)
rx_buf = op->data.buf.in;
else
tx_buf = op->data.buf.out;
}Quoted 9 lines
drivers/spi/spi-mem.c +0
-8-/* -* Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so -* we're guaranteed that this buffer is DMA-able, as required by the -* SPI layer. -*/ - tx_buf =kzalloc (xfer_len,GFP_KERNEL ); -if (!tx_buf) -return -ENOMEM ;
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 346
Quoted 10 lines
drivers/spi/spi-mem.c +4
-5- -if (rx_data) { - rx_buf =kzalloc (xfer_len,GFP_KERNEL ); -if (!rx_buf) -return -ENOMEM ; + op_len =sizeof (op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; +if (op_len >OP_BUFFER_SIZE_MAX ) { +printf ("Length for cmd+addr+dummy too big (%d)\n" , op_len); +return -EIO ; }
While I agree we shouldn't exceed the 16 bytes for cmd, addr and dummy cycles, I'm not a big fan of those hardcoded limitations that needs to be adjusted every time we realize the initial choice was too restrictive.
Do you have a good reason for avoiding kzalloc() here (perfs, dynamic allocation not available in some cases?)?
Quoted 20 lines
drivers/spi/spi-mem.c +4
-4+memset (op_buf,0x00 , op_len); ret =spi_claim_bus (slave);if (ret <0 )return ret; - tx_buf[pos++] = op->cmd.opcode; + op_buf[pos++] = op->cmd.opcode;if (op->addr.nbytes) {for (i =0 ; i < op->addr.nbytes; i++) - tx_buf[pos + i] = op->addr.val >> - (8 * (op->addr.nbytes - i -1 )); + op_buf[pos + i] = op->addr.val >> + (8 * (op->addr.nbytes - i -1 )); pos += op->addr.nbytes; } -if (op->dummy.nbytes) {
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 370
Quoted 10 lines
drivers/spi/spi-mem.c +8
-2-memset (tx_buf + pos,0xff , op->dummy.nbytes); - pos += op->dummy.nbytes; +if (op->dummy.nbytes) +memset (op_buf + pos,0xff , op->dummy.nbytes); + +/* 1st transfer: opcode + address + dummy cycles */ + flag =SPI_XFER_BEGIN ; +/* Make sure to set END bit if no tx or rx data messages follow */ +if (!tx_data && !rx_data) + flag |=SPI_XFER_END ;
I'd add a blank line here.
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 371
Quoted 1 line
drivers/spi/spi-mem.c +1
-0+ ret =spi_xfer (slave, op_len *8 , op_buf,NULL , flag);
You should check ret here.
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 376
Quoted 5 lines
drivers/spi/spi-mem.c +5
-0+ +if (tx_data) { +/* 2nd transfer a: tx data path */ + ret =spi_xfer (slave, op->data.nbytes *8 , tx_buf,NULL , +SPI_XFER_END );
and here
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 382
Quoted 8 lines
drivers/spi/spi-mem.c +4
-2} -if (tx_data) -memcpy (tx_buf + pos, op->data.buf.out, op->data.nbytes); +if (rx_data) { +/* 2nd transfer b: rx data path */ + ret =spi_xfer (slave, op->data.nbytes *8 ,NULL , rx_buf, +SPI_XFER_END );
and here
drivers/spi/spi-mem.c int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) · line 383
Quoted 1 line
drivers/spi/spi-mem.c +1
-0+ }
If you've initialized rx/tx_buf as suggested above, you can do:
if (tx_buf || rx_buf) {
ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
rx_buf, SPI_XFER_END);
if (ret)
return ret;
}Quoted 27 lines
drivers/spi/spi-mem.c +2
-10- ret =spi_xfer (slave, xfer_len *8 , tx_buf, rx_buf, -SPI_XFER_BEGIN |SPI_XFER_END );spi_release_bus (slave);for (i =0 ; i < pos; i++) -debug ("%02x " , tx_buf[i]); +debug ("%02x " , op_buf[i]);debug ("| [%dB %s] " , tx_data || rx_data ? op->data.nbytes :0 , tx_data || rx_data ? (tx_data ?"out" :"in" ) :"-" ); -for (; i < xfer_len; i++) +for (i =0 ; i < op->data.nbytes; i++)debug ("%02x " , tx_data ? tx_buf[i] : rx_buf[i]);debug ("[ret %d]\n" , ret);if (ret <0 )return ret; - -if (rx_data) -memcpy (op->data.buf.in, rx_buf + pos, op->data.nbytes); - -kfree (tx_buf); -kfree (rx_buf);#endif /* __UBOOT__ */ return 0 ;
Miquel Raynal
maintainerPATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Stefan, Jagan,
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 16 lines
Quoted 4 lines · On Tue, 7 Aug 2018 14:16:52 +0200 Stefan Roese <[email protected]> wrote:
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>
Quoted 5 lines
Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Reviewed-by Boris Brezillon <[email protected]>
Sorry for being a bit late on the discussion, but while I do agree with the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Would it be possible to adapt spi_xfer() to handle such case?
Thanks,
Miquèl
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Miquel,
Quoted 25 lines · Miquel Raynal
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 16 lines
Quoted 4 lines · On Tue, 7 Aug 2018 14:16:52 +0200 Stefan Roese <[email protected]> wrote:
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>Quoted 5 lines
Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Reviewed-by Boris Brezillon <[email protected]>
Quoted 7 lines
Sorry for being a bit late on the discussion, but while I do agree with the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Would it be possible to adapt
spi_xfer()to handle such case?
No, I don't think so. Its impossible to guess in the SPI driver layer, which parts of the message are TX data and which are RX data. So this message can't be split up into a half-duplex one here. This can only be done in the driver which constructs the SPI messages.
Or did I miss something here?
Thanks,
Stefan
Miquel Raynal
maintainerPATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Stefan,
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 07:24:14 +0200:
Quoted 31 lines
Hi Miquel,
Quoted 28 lines · Miquel Raynal
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 16 lines
Quoted 1 line
On Tue, 7 Aug 2018 14:16:52 +0200
Quoted 4 lines · Stefan Roese
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>Quoted 6 lines
Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Reviewed-by Boris Brezillon <[email protected]>Sorry for being a bit late on the discussion, but while I do agree with
the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Would it be possible to adapt
spi_xfer()to handle such case?No, I don't think so. Its impossible to guess in the SPI driver layer, which parts of the message are TX data and which are RX data. So this message can't be split up into a half-duplex one here. This can only be done in the driver which constructs the SPI messages.
Or did I miss something here?
Actually I'm fine with it as SPI-mem only uses half-duplex. It's not necessary to limit its use to SPI controllers (drivers) supporting full-duplex.
Stefan, shall I fold your changes in my series and resend? Or do I resend only my original patches and Jagan/Tom will apply yours on top of it?
Thanks,
Miquèl
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Miquel,
Quoted 42 lines · Miquel Raynal
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 07:24:14 +0200:
Quoted 31 lines
Hi Miquel,
Quoted 28 lines · Miquel Raynal
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 16 lines
Quoted 1 line
On Tue, 7 Aug 2018 14:16:52 +0200
Quoted 4 lines · Stefan Roese
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>Quoted 6 lines
Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Reviewed-by Boris Brezillon <[email protected]>Sorry for being a bit late on the discussion, but while I do agree with
the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Would it be possible to adapt
spi_xfer()to handle such case?No, I don't think so. Its impossible to guess in the SPI driver layer, which parts of the message are TX data and which are RX data. So this message can't be split up into a half-duplex one here. This can only be done in the driver which constructs the SPI messages.
Or did I miss something here?
Quoted 7 lines
Actually I'm fine with it as SPI-mem only uses half-duplex. It's not necessary to limit its use to SPI controllers (drivers) supporting full-duplex.
Stefan, shall I fold your changes in my series and resend? Or do I resend only my original patches and Jagan/Tom will apply yours on top of it?
Do you need to re-send your original patches? If yes, then please do with my patches folded in. If a re-send is not necessary, then Jagan or Tom should be able to apply your latest patchset and mine on top of it.
Thanks,
Stefan
Miquel Raynal
maintainerPATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Stefan,
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 11:10:15 +0200:
Quoted 45 lines
Hi Miquel,
Quoted 42 lines · Miquel Raynal
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 07:24:14 +0200:
Quoted 32 lines
Quoted 1 line
Hi Miquel,
Quoted 20 lines · Miquel Raynal
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 18 lines
Quoted 1 line
On Tue, 7 Aug 2018 14:16:52 +0200
Quoted 4 lines · Stefan Roese
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Some SPI controller do not support full-duplex SPI transfers. This patch
changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Quoted 8 lines
Quoted 3 lines
Reviewed-by Boris Brezillon <[email protected]>Sorry for being a bit late on the discussion, but while I do agree with
the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Quoted 1 line
Would it be possible to adapt
spi_xfer()to handle such case?Quoted 7 lines
No, I don't think so. Its impossible to guess in the SPI driver layer, which parts of the message are TX data and which are RX data. So this message can't be split up into a half-duplex one here. This can only be done in the driver which constructs the SPI messages.
Or did I miss something here?
Actually I'm fine with it as SPI-mem only uses half-duplex. It's notnecessary to limit its use to SPI controllers (drivers) supporting full-duplex.
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
Stefan, shall I fold your changes in my series and resend? Or do I
resend only my original patches and Jagan/Tom will apply yours on top of it?
Do you need to re-send your original patches? If yes, then please do with my patches folded in. If a re-send is not necessary, then Jagan or Tom should be able to apply your latest patchset and mine on top of it.
I suppose Jagan prefers formal patches than a Github branch so basically I have to pull Boris fixes, squash them, do the same with yours and resend.
As we missed the merge window, maybe I'll also take the time to rework mtdparts. I plan to do that next week.
Thanks for your help,
Miquèl
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Miquel,
Quoted 51 lines · Miquel Raynal
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 11:10:15 +0200:
Quoted 49 lines
Hi Miquel,
Quoted 45 lines · Miquel Raynal
Stefan Roese <[email protected]> wrote on Thu, 9 Aug 2018 07:24:14 +0200:
Quoted 32 lines
Quoted 1 line
Hi Miquel,
Quoted 20 lines · Miquel Raynal
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 18 lines
Quoted 1 line
On Tue, 7 Aug 2018 14:16:52 +0200
Quoted 4 lines · Stefan Roese
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Some SPI controller do not support full-duplex SPI transfers. This patch
changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
Quoted 8 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>Looks good overall, just a few comments (that you might chose to ignore if you disagree).
Quoted 8 lines
Quoted 3 lines
Reviewed-by Boris Brezillon <[email protected]>Sorry for being a bit late on the discussion, but while I do agree with
the change, I'm not sure about its implementation : I think SPI controllers are supposed to be abstracted by the SPI layer. Addressing the controller's limitations in the SPI-mem layer would not be appropriate.
Quoted 1 line
Would it be possible to adapt
spi_xfer()to handle such case?Quoted 7 lines
No, I don't think so. Its impossible to guess in the SPI driver layer, which parts of the message are TX data and which are RX data. So this message can't be split up into a half-duplex one here. This can only be done in the driver which constructs the SPI messages.
Or did I miss something here?
Actually I'm fine with it as SPI-mem only uses half-duplex. It's notnecessary to limit its use to SPI controllers (drivers) supporting full-duplex.
Quoted 1 line
Stefan, shall I fold your changes in my series and resend? Or do I
resend only my original patches and Jagan/Tom will apply yours on top of it?
Quoted 8 lines
Quoted 4 lines
Do you need to re-send your original patches? If yes, then please do with my patches folded in. If a re-send is not necessary, then Jagan or Tom should be able to apply your latest patchset and mine on top of it.
I suppose Jagan prefers formal patches than a Github branch so basically I have to pull Boris fixes, squash them, do the same with yours and resend.
I see. I was not aware, that the fixes from Boris have not been squashed yet. Then re-sending this whole series is probably the best solution.
Quoted 2 lines
As we missed the merge window, maybe I'll also take the time to rework mtdparts. I plan to do that next week.
That would be great.
Thanks,
Stefan
Miquel Raynal
maintainerPATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
In reply to Boris BrezillonHi Stefan,
Minor typo if you decide to send a v3.
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 6 lines
Quoted 3 lines · On Tue, 7 Aug 2018 14:16:52 +0200 Stefan Roese <[email protected]> wrote:
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
^ be ?
Quoted 10 lines
Quoted 9 lines
With this change, no buffers need to be allocated anymore. We use the TX and RX buffers that are passed to
spi_mem_exec_op()directly.Signed-off-by Stefan Roese <[email protected]>Suggested-by Boris Brezillon <[email protected]>Cc Miquel Raynal <[email protected]>Cc Boris Brezillon <[email protected]>Cc Jagan Teki <[email protected]>
Thanks,
Miquèl
PATCH v2 1/4 spi: spi-mem: Use 2 SPI messages instead of a single full-duplex one
Hi Miquel,
Quoted 7 lines · Miquel Raynal
Hi Stefan,
Minor typo if you decide to send a v3.
Boris Brezillon <[email protected]> wrote on Tue, 7 Aug 2018 15:28:02 +0200:
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines · On Tue, 7 Aug 2018 14:16:52 +0200 Stefan Roese <[email protected]> wrote:
Some SPI controller do not support full-duplex SPI transfers. This patch changes the SPI transfer into 2 separate transfers - or 1, if no data is to transmitted.
^ be ?
Thanks. I'll be working an v3 today.
Thanks,
Stefan