brcm63xx: backport upstream solution for SPI message size limits
authorJonas Gorski <jonas.gorski@gmail.com>
Tue, 7 Feb 2017 11:01:46 +0000 (12:01 +0100)
committerJonas Gorski <jonas.gorski@gmail.com>
Sun, 4 Jun 2017 08:40:00 +0000 (10:40 +0200)
Backport upstream solution for working around SPI controller maximum
message sizes.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
18 files changed:
target/linux/brcm63xx/patches-4.4/000-4.5-20-spi-expose-master-transfer-size-limitation.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-01-mtd-spi-nor-change-return-value-of-read-write.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-02-mtd-m25p80-return-amount-of-data-transferred-or-erro.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-03-mtd-fsl-quadspi-return-amount-of-data-read-written-o.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-05-mtd-nxp-spifi-return-amount-of-data-transferred-or-e.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-06-mtd-spi-nor-check-return-value-from-write.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-07-mtd-spi-nor-stop-passing-around-retlen.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-08-mtd-spi-nor-simplify-write-loop.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-09-mtd-spi-nor-add-read-loop.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.8-10-mtd-m25p80-read-in-spi_max_transfer_size-chunks.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/000-4.9-01-spi-introduce-max_message_size-hook-in-spi_master.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/001-4.11-01-mtd-m25p80-consider-max-message-size-in-m25p80_read.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/001-4.12-01-spi-bcm63xx-make-spi-subsystem-aware-of-message-size.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-4.4/202-MTD-DEVICES-m25p80-use-parsers-if-provided-in-flash-.patch
target/linux/brcm63xx/patches-4.4/203-MTD-DEVICES-m25p80-add-support-for-limiting-reads.patch [deleted file]
target/linux/brcm63xx/patches-4.4/411-MIPS-BCM63XX-Register-SPI-flash-if-present.patch
target/linux/brcm63xx/patches-4.4/414-MTD-m25p80-allow-passing-pp_data.patch
target/linux/brcm63xx/patches-4.4/415-MIPS-BCM63XX-export-the-attached-flash-type.patch

diff --git a/target/linux/brcm63xx/patches-4.4/000-4.5-20-spi-expose-master-transfer-size-limitation.patch b/target/linux/brcm63xx/patches-4.4/000-4.5-20-spi-expose-master-transfer-size-limitation.patch
new file mode 100644 (file)
index 0000000..21e037c
--- /dev/null
@@ -0,0 +1,51 @@
+From 4acad4aae10d1fa79a075b38b5c73772c44f576c Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Wed, 2 Dec 2015 10:38:21 +0000
+Subject: [PATCH] spi: expose master transfer size limitation.
+
+On some SPI controllers it is not feasible to transfer arbitrary amount
+of data at once.
+
+When the limit on transfer size is a few kilobytes at least it makes
+sense to use the SPI hardware rather than reverting to gpio driver.
+
+The protocol drivers need a way to check that they do not sent overly
+long messages, though.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ include/linux/spi/spi.h | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -428,6 +428,12 @@ struct spi_master {
+ #define SPI_MASTER_MUST_RX      BIT(3)                /* requires rx */
+ #define SPI_MASTER_MUST_TX      BIT(4)                /* requires tx */
++      /*
++       * on some hardware transfer size may be constrained
++       * the limit may depend on device transfer settings
++       */
++      size_t (*max_transfer_size)(struct spi_device *spi);
++
+       /* lock and mutex for SPI bus locking */
+       spinlock_t              bus_lock_spinlock;
+       struct mutex            bus_lock_mutex;
+@@ -837,6 +843,15 @@ extern int spi_async(struct spi_device *
+ extern int spi_async_locked(struct spi_device *spi,
+                           struct spi_message *message);
++static inline size_t
++spi_max_transfer_size(struct spi_device *spi)
++{
++      struct spi_master *master = spi->master;
++      if (!master->max_transfer_size)
++              return SIZE_MAX;
++      return master->max_transfer_size(spi);
++}
++
+ /*---------------------------------------------------------------------------*/
+ /* All these synchronous SPI transfer routines are utilities layered
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-01-mtd-spi-nor-change-return-value-of-read-write.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-01-mtd-spi-nor-change-return-value-of-read-write.patch
new file mode 100644 (file)
index 0000000..31c24e5
--- /dev/null
@@ -0,0 +1,149 @@
+From 59451e1233bd315c5379a631838a03d80e689581 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:47 -0700
+Subject: [PATCH 01/10] mtd: spi-nor: change return value of read/write
+
+Change the return value of spi-nor device read and write methods to
+allow returning amount of data transferred and errors as
+read(2)/write(2) does.
+
+Also, start handling positive returns in spi_nor_read(), since we want
+to convert drivers to start returning the read-length both via *retlen
+and the return code. (We don't need to do the same transition process
+for spi_nor_write(), since ->write() didn't used to have a return code
+at all.)
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c      |  5 +++--
+ drivers/mtd/spi-nor/fsl-quadspi.c |  5 +++--
+ drivers/mtd/spi-nor/nxp-spifi.c   | 12 ++++++------
+ drivers/mtd/spi-nor/spi-nor.c     |  5 ++++-
+ include/linux/mtd/spi-nor.h       |  4 ++--
+ 6 files changed, 36 insertions(+), 21 deletions(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -73,7 +73,7 @@ static int m25p80_write_reg(struct spi_n
+       return spi_write(spi, flash->command, len + 1);
+ }
+-static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
++static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+ {
+       struct m25p *flash = nor->priv;
+@@ -101,6 +101,7 @@ static void m25p80_write(struct spi_nor
+       spi_sync(spi, &m);
+       *retlen += m.actual_length - cmd_sz;
++      return 0;
+ }
+ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+@@ -119,7 +120,7 @@ static inline unsigned int m25p80_rx_nbi
+  * Read an address range from the nor chip.  The address range
+  * may be any size provided it is within the physical boundaries.
+  */
+-static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
++static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
+ {
+       struct m25p *flash = nor->priv;
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -822,7 +822,7 @@ static int fsl_qspi_write_reg(struct spi
+       return ret;
+ }
+-static void fsl_qspi_write(struct spi_nor *nor, loff_t to,
++static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
+               size_t len, size_t *retlen, const u_char *buf)
+ {
+       struct fsl_qspi *q = nor->priv;
+@@ -832,9 +832,10 @@ static void fsl_qspi_write(struct spi_no
+       /* invalid the data in the AHB buffer. */
+       fsl_qspi_invalid(q);
++      return 0;
+ }
+-static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
++static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
+               size_t len, size_t *retlen, u_char *buf)
+ {
+       struct fsl_qspi *q = nor->priv;
+--- a/drivers/mtd/spi-nor/nxp-spifi.c
++++ b/drivers/mtd/spi-nor/nxp-spifi.c
+@@ -172,8 +172,8 @@ static int nxp_spifi_write_reg(struct sp
+       return nxp_spifi_wait_for_cmd(spifi);
+ }
+-static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
+-                        size_t *retlen, u_char *buf)
++static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
++                            size_t *retlen, u_char *buf)
+ {
+       struct nxp_spifi *spifi = nor->priv;
+       int ret;
+@@ -188,8 +188,8 @@ static int nxp_spifi_read(struct spi_nor
+       return 0;
+ }
+-static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
+-                          size_t *retlen, const u_char *buf)
++static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
++                             size_t *retlen, const u_char *buf)
+ {
+       struct nxp_spifi *spifi = nor->priv;
+       u32 cmd;
+@@ -197,7 +197,7 @@ static void nxp_spifi_write(struct spi_n
+       ret = nxp_spifi_set_memory_mode_off(spifi);
+       if (ret)
+-              return;
++              return ret;
+       writel(to, spifi->io_base + SPIFI_ADDR);
+       *retlen += len;
+@@ -212,7 +212,7 @@ static void nxp_spifi_write(struct spi_n
+       while (len--)
+               writeb(*buf++, spifi->io_base + SPIFI_DATA);
+-      nxp_spifi_wait_for_cmd(spifi);
++      return nxp_spifi_wait_for_cmd(spifi);
+ }
+ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -893,7 +893,10 @@ static int spi_nor_read(struct mtd_info
+       ret = nor->read(nor, from, len, retlen, buf);
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+-      return ret;
++      if (ret < 0)
++              return ret;
++
++      return 0;
+ }
+ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -169,9 +169,9 @@ struct spi_nor {
+       int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+-      int (*read)(struct spi_nor *nor, loff_t from,
++      ssize_t (*read)(struct spi_nor *nor, loff_t from,
+                       size_t len, size_t *retlen, u_char *read_buf);
+-      void (*write)(struct spi_nor *nor, loff_t to,
++      ssize_t (*write)(struct spi_nor *nor, loff_t to,
+                       size_t len, size_t *retlen, const u_char *write_buf);
+       int (*erase)(struct spi_nor *nor, loff_t offs);
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-02-mtd-m25p80-return-amount-of-data-transferred-or-erro.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-02-mtd-m25p80-return-amount-of-data-transferred-or-erro.patch
new file mode 100644 (file)
index 0000000..fb89b77
--- /dev/null
@@ -0,0 +1,91 @@
+From 1992297b0810a42d78ec7b4de15304eb0489fd97 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:48 -0700
+Subject: [PATCH 02/10] mtd: m25p80: return amount of data transferred or error
+ in read/write
+
+Add checking of SPI transfer errors and return them from read/write
+functions. Also return the amount of data transferred.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c | 29 +++++++++++++++++++++--------
+ 1 file changed, 21 insertions(+), 8 deletions(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -81,6 +81,7 @@ static ssize_t m25p80_write(struct spi_n
+       struct spi_transfer t[2] = {};
+       struct spi_message m;
+       int cmd_sz = m25p_cmdsz(nor);
++      ssize_t ret;
+       spi_message_init(&m);
+@@ -98,10 +99,15 @@ static ssize_t m25p80_write(struct spi_n
+       t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
+-      spi_sync(spi, &m);
++      ret = spi_sync(spi, &m);
++      if (ret)
++              return ret;
+-      *retlen += m.actual_length - cmd_sz;
+-      return 0;
++      ret = m.actual_length - cmd_sz;
++      if (ret < 0)
++              return -EIO;
++      *retlen += ret;
++      return ret;
+ }
+ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+@@ -128,13 +134,13 @@ static ssize_t m25p80_read(struct spi_no
+       struct spi_transfer t[2];
+       struct spi_message m;
+       unsigned int dummy = nor->read_dummy;
++      ssize_t ret;
+       /* convert the dummy cycles to the number of bytes */
+       dummy /= 8;
+       if (spi_flash_read_supported(spi)) {
+               struct spi_flash_read_message msg;
+-              int ret;
+               memset(&msg, 0, sizeof(msg));
+@@ -151,7 +157,9 @@ static ssize_t m25p80_read(struct spi_no
+               ret = spi_flash_read(spi, &msg);
+               *retlen = msg.retlen;
+-              return ret;
++              if (ret < 0)
++                      return ret;
++              return msg.retlen;
+       }
+       spi_message_init(&m);
+@@ -169,10 +177,15 @@ static ssize_t m25p80_read(struct spi_no
+       t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
+-      spi_sync(spi, &m);
++      ret = spi_sync(spi, &m);
++      if (ret)
++              return ret;
+-      *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
+-      return 0;
++      ret = m.actual_length - m25p_cmdsz(nor) - dummy;
++      if (ret < 0)
++              return -EIO;
++      *retlen += ret;
++      return ret;
+ }
+ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-03-mtd-fsl-quadspi-return-amount-of-data-read-written-o.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-03-mtd-fsl-quadspi-return-amount-of-data-read-written-o.patch
new file mode 100644 (file)
index 0000000..232f11c
--- /dev/null
@@ -0,0 +1,72 @@
+From fc0d7e542a0d4193521899d15f8f4999dc295323 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:49 -0700
+Subject: [PATCH 03/10] mtd: fsl-quadspi: return amount of data read/written or
+ error
+
+Return amount of data read/written or error as read(2)/write(2) does.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/fsl-quadspi.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -575,7 +575,7 @@ static inline void fsl_qspi_invalid(stru
+       writel(reg, q->iobase + QUADSPI_MCR);
+ }
+-static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
++static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+                               u8 opcode, unsigned int to, u32 *txbuf,
+                               unsigned count, size_t *retlen)
+ {
+@@ -604,8 +604,11 @@ static int fsl_qspi_nor_write(struct fsl
+       /* Trigger it */
+       ret = fsl_qspi_runcmd(q, opcode, to, count);
+-      if (ret == 0 && retlen)
+-              *retlen += count;
++      if (ret == 0) {
++              if (retlen)
++                      *retlen += count;
++              return count;
++      }
+       return ret;
+ }
+@@ -814,6 +817,8 @@ static int fsl_qspi_write_reg(struct spi
+       } else if (len > 0) {
+               ret = fsl_qspi_nor_write(q, nor, opcode, 0,
+                                       (u32 *)buf, len, NULL);
++              if (ret > 0)
++                      return 0;
+       } else {
+               dev_err(q->dev, "invalid cmd %d\n", opcode);
+               ret = -EINVAL;
+@@ -827,12 +832,12 @@ static ssize_t fsl_qspi_write(struct spi
+ {
+       struct fsl_qspi *q = nor->priv;
+-      fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
++      ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+                               (u32 *)buf, len, retlen);
+       /* invalid the data in the AHB buffer. */
+       fsl_qspi_invalid(q);
+-      return 0;
++      return ret;
+ }
+ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
+@@ -879,7 +884,7 @@ static ssize_t fsl_qspi_read(struct spi_
+               len);
+       *retlen += len;
+-      return 0;
++      return len;
+ }
+ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-05-mtd-nxp-spifi-return-amount-of-data-transferred-or-e.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-05-mtd-nxp-spifi-return-amount-of-data-transferred-or-e.patch
new file mode 100644 (file)
index 0000000..0458148
--- /dev/null
@@ -0,0 +1,51 @@
+From bc418cd2652f47a327e27f978caa3d85f9558b09 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Thu, 5 May 2016 17:31:51 -0700
+Subject: [PATCH 05/10] mtd: nxp-spifi: return amount of data transferred or
+ error in read/write
+
+Add checking of SPI transfer errors and return them from read/write
+functions. Also return the amount of data transferred.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/nxp-spifi.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/mtd/spi-nor/nxp-spifi.c
++++ b/drivers/mtd/spi-nor/nxp-spifi.c
+@@ -185,7 +185,7 @@ static ssize_t nxp_spifi_read(struct spi
+       memcpy_fromio(buf, spifi->flash_base + from, len);
+       *retlen += len;
+-      return 0;
++      return len;
+ }
+ static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
+@@ -194,6 +194,7 @@ static ssize_t nxp_spifi_write(struct sp
+       struct nxp_spifi *spifi = nor->priv;
+       u32 cmd;
+       int ret;
++      size_t i;
+       ret = nxp_spifi_set_memory_mode_off(spifi);
+       if (ret)
+@@ -209,10 +210,14 @@ static ssize_t nxp_spifi_write(struct sp
+             SPIFI_CMD_FRAMEFORM(spifi->nor.addr_width + 1);
+       writel(cmd, spifi->io_base + SPIFI_CMD);
+-      while (len--)
+-              writeb(*buf++, spifi->io_base + SPIFI_DATA);
++      for (i = 0; i < len; i++)
++              writeb(buf[i], spifi->io_base + SPIFI_DATA);
+-      return nxp_spifi_wait_for_cmd(spifi);
++      ret = nxp_spifi_wait_for_cmd(spifi);
++      if (ret)
++              return ret;
++
++      return len;
+ }
+ static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-06-mtd-spi-nor-check-return-value-from-write.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-06-mtd-spi-nor-check-return-value-from-write.patch
new file mode 100644 (file)
index 0000000..0bdcccf
--- /dev/null
@@ -0,0 +1,118 @@
+From 0bad7b9304d543dd7627f4cd564aea5d7338b950 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:52 -0700
+Subject: [PATCH 06/10] mtd: spi-nor: check return value from write
+
+SPI NOR hardware drivers now return useful value from their write
+functions so check them.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 45 ++++++++++++++++++++++++++++++-------------
+ 1 file changed, 32 insertions(+), 13 deletions(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -922,10 +922,14 @@ static int sst_write(struct mtd_info *mt
+               nor->program_opcode = SPINOR_OP_BP;
+               /* write one byte. */
+-              nor->write(nor, to, 1, retlen, buf);
++              ret = nor->write(nor, to, 1, retlen, buf);
++              if (ret < 0)
++                      goto sst_write_err;
++              WARN(ret != 1, "While writing 1 byte written %i bytes\n",
++                   (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+-                      goto time_out;
++                      goto sst_write_err;
+       }
+       to += actual;
+@@ -934,10 +938,14 @@ static int sst_write(struct mtd_info *mt
+               nor->program_opcode = SPINOR_OP_AAI_WP;
+               /* write two bytes. */
+-              nor->write(nor, to, 2, retlen, buf + actual);
++              ret = nor->write(nor, to, 2, retlen, buf + actual);
++              if (ret < 0)
++                      goto sst_write_err;
++              WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
++                   (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+-                      goto time_out;
++                      goto sst_write_err;
+               to += 2;
+               nor->sst_write_second = true;
+       }
+@@ -946,21 +954,24 @@ static int sst_write(struct mtd_info *mt
+       write_disable(nor);
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+-              goto time_out;
++              goto sst_write_err;
+       /* Write out trailing byte if it exists. */
+       if (actual != len) {
+               write_enable(nor);
+               nor->program_opcode = SPINOR_OP_BP;
+-              nor->write(nor, to, 1, retlen, buf + actual);
+-
++              ret = nor->write(nor, to, 1, retlen, buf + actual);
++              if (ret < 0)
++                      goto sst_write_err;
++              WARN(ret != 1, "While writing 1 byte written %i bytes\n",
++                   (int)ret);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+-                      goto time_out;
++                      goto sst_write_err;
+               write_disable(nor);
+       }
+-time_out:
++sst_write_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
+ }
+@@ -989,14 +1000,18 @@ static int spi_nor_write(struct mtd_info
+       /* do all the bytes fit onto one page? */
+       if (page_offset + len <= nor->page_size) {
+-              nor->write(nor, to, len, retlen, buf);
++              ret = nor->write(nor, to, len, retlen, buf);
++              if (ret < 0)
++                      goto write_err;
+       } else {
+               /* the size of data remaining on the first page */
+               page_size = nor->page_size - page_offset;
+-              nor->write(nor, to, page_size, retlen, buf);
++              ret = nor->write(nor, to, page_size, retlen, buf);
++              if (ret < 0)
++                      goto write_err;
+               /* write everything in nor->page_size chunks */
+-              for (i = page_size; i < len; i += page_size) {
++              for (i = ret; i < len; ) {
+                       page_size = len - i;
+                       if (page_size > nor->page_size)
+                               page_size = nor->page_size;
+@@ -1007,7 +1022,11 @@ static int spi_nor_write(struct mtd_info
+                       write_enable(nor);
+-                      nor->write(nor, to + i, page_size, retlen, buf + i);
++                      ret = nor->write(nor, to + i, page_size, retlen,
++                                       buf + i);
++                      if (ret < 0)
++                              goto write_err;
++                      i += ret;
+               }
+       }
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-07-mtd-spi-nor-stop-passing-around-retlen.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-07-mtd-spi-nor-stop-passing-around-retlen.patch
new file mode 100644 (file)
index 0000000..9949d35
--- /dev/null
@@ -0,0 +1,266 @@
+From 2dd087b16946cf168f401526adf26afa771bb740 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:53 -0700
+Subject: [PATCH 07/10] mtd: spi-nor: stop passing around retlen
+
+Do not pass retlen to hardware driver read/write functions. Update it in
+spi-nor generic driver instead.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c      |  7 ++-----
+ drivers/mtd/spi-nor/fsl-quadspi.c | 17 ++++++-----------
+ drivers/mtd/spi-nor/nxp-spifi.c   |  6 ++----
+ drivers/mtd/spi-nor/spi-nor.c     | 21 +++++++++++++--------
+ include/linux/mtd/spi-nor.h       |  4 ++--
+ 6 files changed, 28 insertions(+), 35 deletions(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -74,7 +74,7 @@ static int m25p80_write_reg(struct spi_n
+ }
+ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+-                      size_t *retlen, const u_char *buf)
++                          const u_char *buf)
+ {
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
+@@ -106,7 +106,6 @@ static ssize_t m25p80_write(struct spi_n
+       ret = m.actual_length - cmd_sz;
+       if (ret < 0)
+               return -EIO;
+-      *retlen += ret;
+       return ret;
+ }
+@@ -127,7 +126,7 @@ static inline unsigned int m25p80_rx_nbi
+  * may be any size provided it is within the physical boundaries.
+  */
+ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+-                      size_t *retlen, u_char *buf)
++                         u_char *buf)
+ {
+       struct m25p *flash = nor->priv;
+       struct spi_device *spi = flash->spi;
+@@ -156,7 +155,6 @@ static ssize_t m25p80_read(struct spi_no
+               msg.data_nbits = m25p80_rx_nbits(nor);
+               ret = spi_flash_read(spi, &msg);
+-              *retlen = msg.retlen;
+               if (ret < 0)
+                       return ret;
+               return msg.retlen;
+@@ -184,7 +182,6 @@ static ssize_t m25p80_read(struct spi_no
+       ret = m.actual_length - m25p_cmdsz(nor) - dummy;
+       if (ret < 0)
+               return -EIO;
+-      *retlen += ret;
+       return ret;
+ }
+--- a/drivers/mtd/spi-nor/fsl-quadspi.c
++++ b/drivers/mtd/spi-nor/fsl-quadspi.c
+@@ -577,7 +577,7 @@ static inline void fsl_qspi_invalid(stru
+ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+                               u8 opcode, unsigned int to, u32 *txbuf,
+-                              unsigned count, size_t *retlen)
++                              unsigned count)
+ {
+       int ret, i, j;
+       u32 tmp;
+@@ -604,11 +604,8 @@ static ssize_t fsl_qspi_nor_write(struct
+       /* Trigger it */
+       ret = fsl_qspi_runcmd(q, opcode, to, count);
+-      if (ret == 0) {
+-              if (retlen)
+-                      *retlen += count;
++      if (ret == 0)
+               return count;
+-      }
+       return ret;
+ }
+@@ -816,7 +813,7 @@ static int fsl_qspi_write_reg(struct spi
+       } else if (len > 0) {
+               ret = fsl_qspi_nor_write(q, nor, opcode, 0,
+-                                      (u32 *)buf, len, NULL);
++                                      (u32 *)buf, len);
+               if (ret > 0)
+                       return 0;
+       } else {
+@@ -828,12 +825,11 @@ static int fsl_qspi_write_reg(struct spi
+ }
+ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
+-              size_t len, size_t *retlen, const u_char *buf)
++                            size_t len, const u_char *buf)
+ {
+       struct fsl_qspi *q = nor->priv;
+-
+       ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+-                              (u32 *)buf, len, retlen);
++                                       (u32 *)buf, len);
+       /* invalid the data in the AHB buffer. */
+       fsl_qspi_invalid(q);
+@@ -841,7 +837,7 @@ static ssize_t fsl_qspi_write(struct spi
+ }
+ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
+-              size_t len, size_t *retlen, u_char *buf)
++                           size_t len, u_char *buf)
+ {
+       struct fsl_qspi *q = nor->priv;
+       u8 cmd = nor->read_opcode;
+@@ -883,7 +879,6 @@ static ssize_t fsl_qspi_read(struct spi_
+       memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
+               len);
+-      *retlen += len;
+       return len;
+ }
+--- a/drivers/mtd/spi-nor/nxp-spifi.c
++++ b/drivers/mtd/spi-nor/nxp-spifi.c
+@@ -173,7 +173,7 @@ static int nxp_spifi_write_reg(struct sp
+ }
+ static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
+-                            size_t *retlen, u_char *buf)
++                            u_char *buf)
+ {
+       struct nxp_spifi *spifi = nor->priv;
+       int ret;
+@@ -183,13 +183,12 @@ static ssize_t nxp_spifi_read(struct spi
+               return ret;
+       memcpy_fromio(buf, spifi->flash_base + from, len);
+-      *retlen += len;
+       return len;
+ }
+ static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
+-                             size_t *retlen, const u_char *buf)
++                             const u_char *buf)
+ {
+       struct nxp_spifi *spifi = nor->priv;
+       u32 cmd;
+@@ -201,7 +200,6 @@ static ssize_t nxp_spifi_write(struct sp
+               return ret;
+       writel(to, spifi->io_base + SPIFI_ADDR);
+-      *retlen += len;
+       cmd = SPIFI_CMD_DOUT |
+             SPIFI_CMD_DATALEN(len) |
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -890,12 +890,13 @@ static int spi_nor_read(struct mtd_info
+       if (ret)
+               return ret;
+-      ret = nor->read(nor, from, len, retlen, buf);
++      ret = nor->read(nor, from, len, buf);
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+       if (ret < 0)
+               return ret;
++      *retlen += ret;
+       return 0;
+ }
+@@ -922,7 +923,7 @@ static int sst_write(struct mtd_info *mt
+               nor->program_opcode = SPINOR_OP_BP;
+               /* write one byte. */
+-              ret = nor->write(nor, to, 1, retlen, buf);
++              ret = nor->write(nor, to, 1, buf);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+@@ -938,7 +939,7 @@ static int sst_write(struct mtd_info *mt
+               nor->program_opcode = SPINOR_OP_AAI_WP;
+               /* write two bytes. */
+-              ret = nor->write(nor, to, 2, retlen, buf + actual);
++              ret = nor->write(nor, to, 2, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
+@@ -961,7 +962,7 @@ static int sst_write(struct mtd_info *mt
+               write_enable(nor);
+               nor->program_opcode = SPINOR_OP_BP;
+-              ret = nor->write(nor, to, 1, retlen, buf + actual);
++              ret = nor->write(nor, to, 1, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+@@ -970,8 +971,10 @@ static int sst_write(struct mtd_info *mt
+               if (ret)
+                       goto sst_write_err;
+               write_disable(nor);
++              actual += 1;
+       }
+ sst_write_err:
++      *retlen += actual;
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
+ }
+@@ -1000,15 +1003,17 @@ static int spi_nor_write(struct mtd_info
+       /* do all the bytes fit onto one page? */
+       if (page_offset + len <= nor->page_size) {
+-              ret = nor->write(nor, to, len, retlen, buf);
++              ret = nor->write(nor, to, len, buf);
+               if (ret < 0)
+                       goto write_err;
++              *retlen += ret;
+       } else {
+               /* the size of data remaining on the first page */
+               page_size = nor->page_size - page_offset;
+-              ret = nor->write(nor, to, page_size, retlen, buf);
++              ret = nor->write(nor, to, page_size, buf);
+               if (ret < 0)
+                       goto write_err;
++              *retlen += ret;
+               /* write everything in nor->page_size chunks */
+               for (i = ret; i < len; ) {
+@@ -1022,10 +1027,10 @@ static int spi_nor_write(struct mtd_info
+                       write_enable(nor);
+-                      ret = nor->write(nor, to + i, page_size, retlen,
+-                                       buf + i);
++                      ret = nor->write(nor, to + i, page_size, buf + i);
+                       if (ret < 0)
+                               goto write_err;
++                      *retlen += ret;
+                       i += ret;
+               }
+       }
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -170,9 +170,9 @@ struct spi_nor {
+       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+       ssize_t (*read)(struct spi_nor *nor, loff_t from,
+-                      size_t len, size_t *retlen, u_char *read_buf);
++                      size_t len, u_char *read_buf);
+       ssize_t (*write)(struct spi_nor *nor, loff_t to,
+-                      size_t len, size_t *retlen, const u_char *write_buf);
++                      size_t len, const u_char *write_buf);
+       int (*erase)(struct spi_nor *nor, loff_t offs);
+       int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-08-mtd-spi-nor-simplify-write-loop.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-08-mtd-spi-nor-simplify-write-loop.patch
new file mode 100644 (file)
index 0000000..b2e840d
--- /dev/null
@@ -0,0 +1,103 @@
+From e5d05cbd6d8b01f08c95c427a36c66aac769af4f Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:54 -0700
+Subject: [PATCH 08/10] mtd: spi-nor: simplify write loop
+
+The spi-nor write loop assumes that what is passed to the hardware
+driver write() is what gets written.
+
+When write() writes less than page size at once data is dropped on the
+floor. Check the amount of data writen and exit if it does not match
+requested amount.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 58 +++++++++++++++++++------------------------
+ 1 file changed, 25 insertions(+), 33 deletions(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -988,8 +988,8 @@ static int spi_nor_write(struct mtd_info
+       size_t *retlen, const u_char *buf)
+ {
+       struct spi_nor *nor = mtd_to_spi_nor(mtd);
+-      u32 page_offset, page_size, i;
+-      int ret;
++      size_t page_offset, page_remain, i;
++      ssize_t ret;
+       dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
+@@ -997,45 +997,37 @@ static int spi_nor_write(struct mtd_info
+       if (ret)
+               return ret;
+-      write_enable(nor);
++      for (i = 0; i < len; ) {
++              ssize_t written;
+-      page_offset = to & (nor->page_size - 1);
+-
+-      /* do all the bytes fit onto one page? */
+-      if (page_offset + len <= nor->page_size) {
+-              ret = nor->write(nor, to, len, buf);
+-              if (ret < 0)
+-                      goto write_err;
+-              *retlen += ret;
+-      } else {
++              page_offset = (to + i) & (nor->page_size - 1);
++              WARN_ONCE(page_offset,
++                        "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
++                        page_offset);
+               /* the size of data remaining on the first page */
+-              page_size = nor->page_size - page_offset;
+-              ret = nor->write(nor, to, page_size, buf);
++              page_remain = min_t(size_t,
++                                  nor->page_size - page_offset, len - i);
++
++              write_enable(nor);
++              ret = nor->write(nor, to + i, page_remain, buf + i);
+               if (ret < 0)
+                       goto write_err;
+-              *retlen += ret;
++              written = ret;
+-              /* write everything in nor->page_size chunks */
+-              for (i = ret; i < len; ) {
+-                      page_size = len - i;
+-                      if (page_size > nor->page_size)
+-                              page_size = nor->page_size;
+-
+-                      ret = spi_nor_wait_till_ready(nor);
+-                      if (ret)
+-                              goto write_err;
+-
+-                      write_enable(nor);
+-
+-                      ret = nor->write(nor, to + i, page_size, buf + i);
+-                      if (ret < 0)
+-                              goto write_err;
+-                      *retlen += ret;
+-                      i += ret;
++              ret = spi_nor_wait_till_ready(nor);
++              if (ret)
++                      goto write_err;
++              *retlen += written;
++              i += written;
++              if (written != page_remain) {
++                      dev_err(nor->dev,
++                              "While writing %zu bytes written %zd bytes\n",
++                              page_remain, written);
++                      ret = -EIO;
++                      goto write_err;
+               }
+       }
+-      ret = spi_nor_wait_till_ready(nor);
+ write_err:
+       spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+       return ret;
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-09-mtd-spi-nor-add-read-loop.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-09-mtd-spi-nor-add-read-loop.patch
new file mode 100644 (file)
index 0000000..662c73a
--- /dev/null
@@ -0,0 +1,54 @@
+From 26f9bcad29a6c240881bd4efc90f16a9990dd6c2 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:55 -0700
+Subject: [PATCH 09/10] mtd: spi-nor: add read loop
+
+mtdblock and ubi do not handle the situation when read returns less data
+than requested. Loop in spi-nor until buffer is filled or an error is
+returned.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -890,14 +890,27 @@ static int spi_nor_read(struct mtd_info
+       if (ret)
+               return ret;
+-      ret = nor->read(nor, from, len, buf);
++      while (len) {
++              ret = nor->read(nor, from, len, buf);
++              if (ret == 0) {
++                      /* We shouldn't see 0-length reads */
++                      ret = -EIO;
++                      goto read_err;
++              }
++              if (ret < 0)
++                      goto read_err;
+-      spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+-      if (ret < 0)
+-              return ret;
++              WARN_ON(ret > len);
++              *retlen += ret;
++              buf += ret;
++              from += ret;
++              len -= ret;
++      }
++      ret = 0;
+-      *retlen += ret;
+-      return 0;
++read_err:
++      spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
++      return ret;
+ }
+ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.8-10-mtd-m25p80-read-in-spi_max_transfer_size-chunks.patch b/target/linux/brcm63xx/patches-4.4/000-4.8-10-mtd-m25p80-read-in-spi_max_transfer_size-chunks.patch
new file mode 100644 (file)
index 0000000..d4f13ec
--- /dev/null
@@ -0,0 +1,26 @@
+From 95193796256cfce16e5d881318e15b6b04062c15 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach@gmail.com>
+Date: Thu, 5 May 2016 17:31:56 -0700
+Subject: [PATCH 10/10] mtd: m25p80: read in spi_max_transfer_size chunks
+
+Take into account transfer size limitation of SPI master.
+
+Signed-off-by: Michal Suchanek <hramrach@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Acked-by: Michal Suchanek <hramrach@gmail.com>
+Tested-by: Michal Suchanek <hramrach@gmail.com>
+---
+ drivers/mtd/devices/m25p80.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -172,7 +172,7 @@ static ssize_t m25p80_read(struct spi_no
+       t[1].rx_buf = buf;
+       t[1].rx_nbits = m25p80_rx_nbits(nor);
+-      t[1].len = len;
++      t[1].len = min(len, spi_max_transfer_size(spi));
+       spi_message_add_tail(&t[1], &m);
+       ret = spi_sync(spi, &m);
diff --git a/target/linux/brcm63xx/patches-4.4/000-4.9-01-spi-introduce-max_message_size-hook-in-spi_master.patch b/target/linux/brcm63xx/patches-4.4/000-4.9-01-spi-introduce-max_message_size-hook-in-spi_master.patch
new file mode 100644 (file)
index 0000000..76a66a3
--- /dev/null
@@ -0,0 +1,73 @@
+From 5090cc6ae2f79ee779e5faf7c8a28edf42b7d738 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Wed, 17 Aug 2016 21:08:01 +0200
+Subject: [PATCH] spi: introduce max_message_size hook in spi_master
+
+Recently a maximum transfer size was was introduced in struct spi_master.
+However there are also spi controllers with a maximum message size, e.g.
+fsl-espi has a max message size of 64KB.
+Introduce a hook max_message_size to deal with such limitations.
+
+Also make sure that spi_max_transfer_size doesn't return greater values
+than spi_max_message_size, even if hook max_transfer_size is not set.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ include/linux/spi/spi.h | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -304,6 +304,8 @@ static inline void spi_unregister_driver
+  * @min_speed_hz: Lowest supported transfer speed
+  * @max_speed_hz: Highest supported transfer speed
+  * @flags: other constraints relevant to this driver
++ * @max_message_size: function that returns the max message size for
++ *    a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
+  * @bus_lock_spinlock: spinlock for SPI bus locking
+  * @bus_lock_mutex: mutex for SPI bus locking
+  * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
+@@ -429,10 +431,11 @@ struct spi_master {
+ #define SPI_MASTER_MUST_TX      BIT(4)                /* requires tx */
+       /*
+-       * on some hardware transfer size may be constrained
++       * on some hardware transfer / message size may be constrained
+        * the limit may depend on device transfer settings
+        */
+       size_t (*max_transfer_size)(struct spi_device *spi);
++      size_t (*max_message_size)(struct spi_device *spi);
+       /* lock and mutex for SPI bus locking */
+       spinlock_t              bus_lock_spinlock;
+@@ -844,12 +847,26 @@ extern int spi_async_locked(struct spi_d
+                           struct spi_message *message);
+ static inline size_t
+-spi_max_transfer_size(struct spi_device *spi)
++spi_max_message_size(struct spi_device *spi)
+ {
+       struct spi_master *master = spi->master;
+-      if (!master->max_transfer_size)
++      if (!master->max_message_size)
+               return SIZE_MAX;
+-      return master->max_transfer_size(spi);
++      return master->max_message_size(spi);
++}
++
++static inline size_t
++spi_max_transfer_size(struct spi_device *spi)
++{
++      struct spi_master *master = spi->master;
++      size_t tr_max = SIZE_MAX;
++      size_t msg_max = spi_max_message_size(spi);
++
++      if (master->max_transfer_size)
++              tr_max = master->max_transfer_size(spi);
++
++      /* transfer size limit must not be greater than messsage size limit */
++      return min(tr_max, msg_max);
+ }
+ /*---------------------------------------------------------------------------*/
diff --git a/target/linux/brcm63xx/patches-4.4/001-4.11-01-mtd-m25p80-consider-max-message-size-in-m25p80_read.patch b/target/linux/brcm63xx/patches-4.4/001-4.11-01-mtd-m25p80-consider-max-message-size-in-m25p80_read.patch
new file mode 100644 (file)
index 0000000..e902701
--- /dev/null
@@ -0,0 +1,30 @@
+From 80a79a889ce5df16c5261ab2f1e8e63b94b78102 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Fri, 28 Oct 2016 07:58:46 +0200
+Subject: [PATCH 1/8] mtd: m25p80: consider max message size in m25p80_read
+
+Consider a message size limit when calculating the maximum amount
+of data that can be read.
+
+The message size limit has been introduced with 4.9, so cc it
+to stable.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Cc: <stable@vger.kernel.org> # 4.9.x
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/devices/m25p80.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_no
+       t[1].rx_buf = buf;
+       t[1].rx_nbits = m25p80_rx_nbits(nor);
+-      t[1].len = min(len, spi_max_transfer_size(spi));
++      t[1].len = min3(len, spi_max_transfer_size(spi),
++                      spi_max_message_size(spi) - t[0].len);
+       spi_message_add_tail(&t[1], &m);
+       ret = spi_sync(spi, &m);
diff --git a/target/linux/brcm63xx/patches-4.4/001-4.12-01-spi-bcm63xx-make-spi-subsystem-aware-of-message-size.patch b/target/linux/brcm63xx/patches-4.4/001-4.12-01-spi-bcm63xx-make-spi-subsystem-aware-of-message-size.patch
new file mode 100644 (file)
index 0000000..d806290
--- /dev/null
@@ -0,0 +1,42 @@
+From 3fcc36962c32ad0af2d5904103e2b2b824b6b1aa Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Sat, 4 Feb 2017 12:32:59 +0100
+Subject: [PATCH 2/8] spi/bcm63xx: make spi subsystem aware of message size
+ limits
+
+The bcm63xx LS SPI controller does not allow manual control of the CS
+lines and will toggle it automatically before after sending data, so we
+are limited to messages that fit in the FIFO buffer. Since the CS lines
+aren't available as GPIOs either, we will need to make slave drivers
+aware of this limitation and handle it accordingly.
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ drivers/spi/spi-bcm63xx.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/spi/spi-bcm63xx.c
++++ b/drivers/spi/spi-bcm63xx.c
+@@ -429,6 +429,13 @@ static irqreturn_t bcm63xx_spi_interrupt
+       return IRQ_HANDLED;
+ }
++static size_t bcm63xx_spi_max_length(struct spi_device *spi)
++{
++      struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
++
++      return bs->fifo_size;
++}
++
+ static const unsigned long bcm6348_spi_reg_offsets[] = {
+       [SPI_CMD]               = SPI_6348_CMD,
+       [SPI_INT_STATUS]        = SPI_6348_INT_STATUS,
+@@ -542,6 +549,8 @@ static int bcm63xx_spi_probe(struct plat
+       master->transfer_one_message = bcm63xx_spi_transfer_one;
+       master->mode_bits = MODEBITS;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
++      master->max_transfer_size = bcm63xx_spi_max_length;
++      master->max_message_size = bcm63xx_spi_max_length;
+       master->auto_runtime_pm = true;
+       bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
+       bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
index 6c26d6c..b0c776a 100644 (file)
@@ -11,7 +11,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
 
 --- a/drivers/mtd/devices/m25p80.c
 +++ b/drivers/mtd/devices/m25p80.c
-@@ -248,8 +248,10 @@ static int m25p_probe(struct spi_device
+@@ -260,8 +260,10 @@ static int m25p_probe(struct spi_device
        if (ret)
                return ret;
  
diff --git a/target/linux/brcm63xx/patches-4.4/203-MTD-DEVICES-m25p80-add-support-for-limiting-reads.patch b/target/linux/brcm63xx/patches-4.4/203-MTD-DEVICES-m25p80-add-support-for-limiting-reads.patch
deleted file mode 100644 (file)
index ddb070c..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-From 5fb4e8d7287ac8fcb33aae8b1e9e22c5a3c392bd Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <jonas.gorski@gmail.com>
-Date: Thu, 10 Nov 2011 17:33:40 +0100
-Subject: [PATCH 51/79] MTD: DEVICES: m25p80: add support for limiting reads
-
-Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
----
- drivers/mtd/devices/m25p80.c |   29 +++++++++++++++++++++++++++--
- include/linux/spi/flash.h    |    4 ++++
- 2 files changed, 31 insertions(+), 2 deletions(-)
-
---- a/drivers/mtd/devices/m25p80.c
-+++ b/drivers/mtd/devices/m25p80.c
-@@ -31,6 +31,7 @@
- struct m25p {
-       struct spi_device       *spi;
-       struct spi_nor          spi_nor;
-+      int                     max_transfer_len;
-       u8                      command[MAX_CMD_SIZE];
- };
-@@ -119,7 +120,7 @@ static inline unsigned int m25p80_rx_nbi
-  * Read an address range from the nor chip.  The address range
-  * may be any size provided it is within the physical boundaries.
-  */
--static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
-+static int __m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf)
- {
-       struct m25p *flash = nor->priv;
-@@ -174,6 +175,29 @@ static int m25p80_read(struct spi_nor *n
-       return 0;
- }
-+static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
-+      size_t *retlen, u_char *buf)
-+{
-+      struct m25p *flash = nor->priv;
-+      size_t off;
-+      size_t read_len = flash->max_transfer_len;
-+      size_t part_len;
-+      int ret = 0;
-+
-+      if (!read_len)
-+              return __m25p80_read(nor, from, len, retlen, buf);
-+
-+      *retlen = 0;
-+
-+      for (off = 0; off < len && !ret; off += read_len) {
-+              ret = __m25p80_read(nor, from + off, min(len - off, read_len),
-+                                  &part_len, buf + off);
-+                      *retlen += part_len;
-+      }
-+
-+      return ret;
-+}
-+
- static int m25p80_erase(struct spi_nor *nor, loff_t offset)
- {
-       struct m25p *flash = nor->priv;
-@@ -244,6 +268,9 @@ static int m25p_probe(struct spi_device
-       else
-               flash_name = spi->modalias;
-+      if (data)
-+              flash->max_transfer_len = data->max_transfer_len;
-+
-       ret = spi_nor_scan(nor, flash_name, mode);
-       if (ret)
-               return ret;
---- a/include/linux/spi/flash.h
-+++ b/include/linux/spi/flash.h
-@@ -13,6 +13,8 @@ struct mtd_part_parser_data;
-  * @part_probe_types: optional list of MTD parser names to use for
-  *    partitioning
-  *
-+ * @max_transfer_len: option maximum read/write length limitation for
-+ *    SPI controllers not able to transfer any length commands.
-  * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
-  * provide information about SPI flash parts (such as DataFlash) to
-  * help set up the device and its appropriate default partitioning.
-@@ -28,6 +30,8 @@ struct flash_platform_data {
-       char            *type;
-       const char      **part_probe_types;
-+
-+      unsigned int    max_transfer_len;
-       /* we'll likely add more ... use JEDEC IDs, etc */
- };
index 0c317cb..1b844fd 100644 (file)
@@ -95,7 +95,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
                if (val & STRAPBUS_63268_BOOT_SEL_SERIAL)
                        return BCM63XX_FLASH_TYPE_SERIAL;
                else
-@@ -195,8 +232,17 @@ int __init bcm63xx_flash_register(void)
+@@ -195,8 +232,14 @@ int __init bcm63xx_flash_register(void)
  
                return platform_device_register(&mtd_dev);
        case BCM63XX_FLASH_TYPE_SERIAL:
@@ -107,9 +107,6 @@ Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
 +                      bcm63xx_spi_flash_info[0].mode = SPI_RX_DUAL;
 +              }
 +
-+              if (BCMCPU_IS_6358() || BCMCPU_IS_6368())
-+                      bcm63xx_flash_data.max_transfer_len = SPI_6358_MSG_DATA_SIZE;
-+
 +              return spi_register_board_info(bcm63xx_spi_flash_info,
 +                                      ARRAY_SIZE(bcm63xx_spi_flash_info));
        case BCM63XX_FLASH_TYPE_NAND:
index a0b4b4f..c565ac0 100644 (file)
@@ -10,7 +10,7 @@ Subject: [PATCH 64/79] MTD: m25p80: allow passing pp_data
 
 --- a/drivers/mtd/devices/m25p80.c
 +++ b/drivers/mtd/devices/m25p80.c
-@@ -276,7 +276,8 @@ static int m25p_probe(struct spi_device
+@@ -261,7 +261,8 @@ static int m25p_probe(struct spi_device
                return ret;
  
        return mtd_device_parse_register(&nor->mtd,
@@ -28,13 +28,13 @@ Subject: [PATCH 64/79] MTD: m25p80: allow passing pp_data
   *    partitioning
 + * @pp_data: optional partition parser data.
   *
-  * @max_transfer_len: option maximum read/write length limitation for
-  *    SPI controllers not able to transfer any length commands.
-@@ -30,6 +31,7 @@ struct flash_platform_data {
+  * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
+  * provide information about SPI flash parts (such as DataFlash) to
+@@ -28,6 +29,7 @@ struct flash_platform_data {
        char            *type;
  
        const char      **part_probe_types;
 +      struct mtd_part_parser_data *pp_data;
-       unsigned int    max_transfer_len;
        /* we'll likely add more ... use JEDEC IDs, etc */
+ };
index d874059..02ecbf7 100644 (file)
@@ -11,7 +11,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
 
 --- a/arch/mips/bcm63xx/dev-flash.c
 +++ b/arch/mips/bcm63xx/dev-flash.c
-@@ -252,3 +252,8 @@ int __init bcm63xx_flash_register(void)
+@@ -249,3 +249,8 @@ int __init bcm63xx_flash_register(void)
                return -ENODEV;
        }
  }