[source] brcm63xx: backport upstream solution for SPI message size limits
LEDE Commits
lede-commits at lists.infradead.org
Sun Jun 4 02:35:38 PDT 2017
jogo pushed a commit to source.git, branch master:
https://git.lede-project.org/2a2b16210bbc8c5881286d2ff742f3bdf1a7fd9c
commit 2a2b16210bbc8c5881286d2ff742f3bdf1a7fd9c
Author: Jonas Gorski <jonas.gorski at gmail.com>
AuthorDate: Tue Feb 7 12:01:46 2017 +0100
brcm63xx: backport upstream solution for SPI message size limits
Backport upstream solution for working around SPI controller maximum
message sizes.
Signed-off-by: Jonas Gorski <jonas.gorski at gmail.com>
---
...pi-expose-master-transfer-size-limitation.patch | 51 ++++
...spi-nor-change-return-value-of-read-write.patch | 149 ++++++++++++
...return-amount-of-data-transferred-or-erro.patch | 91 +++++++
...dspi-return-amount-of-data-read-written-o.patch | 72 ++++++
...fi-return-amount-of-data-transferred-or-e.patch | 51 ++++
...mtd-spi-nor-check-return-value-from-write.patch | 118 +++++++++
...07-mtd-spi-nor-stop-passing-around-retlen.patch | 266 +++++++++++++++++++++
...00-4.8-08-mtd-spi-nor-simplify-write-loop.patch | 103 ++++++++
.../000-4.8-09-mtd-spi-nor-add-read-loop.patch | 54 +++++
...5p80-read-in-spi_max_transfer_size-chunks.patch | 26 ++
...oduce-max_message_size-hook-in-spi_master.patch | 73 ++++++
...-consider-max-message-size-in-m25p80_read.patch | 30 +++
...-make-spi-subsystem-aware-of-message-size.patch | 42 ++++
...-m25p80-use-parsers-if-provided-in-flash-.patch | 2 +-
...CES-m25p80-add-support-for-limiting-reads.patch | 90 -------
...IPS-BCM63XX-Register-SPI-flash-if-present.patch | 5 +-
.../414-MTD-m25p80-allow-passing-pp_data.patch | 12 +-
...PS-BCM63XX-export-the-attached-flash-type.patch | 2 +-
18 files changed, 1135 insertions(+), 102 deletions(-)
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
index 0000000..21e037c
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.5-20-spi-expose-master-transfer-size-limitation.patch
@@ -0,0 +1,51 @@
+From 4acad4aae10d1fa79a075b38b5c73772c44f576c Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Mark Brown <broonie at 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
index 0000000..31c24e5
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-01-mtd-spi-nor-change-return-value-of-read-write.patch
@@ -0,0 +1,149 @@
+From 59451e1233bd315c5379a631838a03d80e689581 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..fb89b77
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-02-mtd-m25p80-return-amount-of-data-transferred-or-erro.patch
@@ -0,0 +1,91 @@
+From 1992297b0810a42d78ec7b4de15304eb0489fd97 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..232f11c
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-03-mtd-fsl-quadspi-return-amount-of-data-read-written-o.patch
@@ -0,0 +1,72 @@
+From fc0d7e542a0d4193521899d15f8f4999dc295323 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at 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
index 0000000..0458148
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-05-mtd-nxp-spifi-return-amount-of-data-transferred-or-e.patch
@@ -0,0 +1,51 @@
+From bc418cd2652f47a327e27f978caa3d85f9558b09 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at 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 at 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
index 0000000..0bdcccf
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-06-mtd-spi-nor-check-return-value-from-write.patch
@@ -0,0 +1,118 @@
+From 0bad7b9304d543dd7627f4cd564aea5d7338b950 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..9949d35
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-07-mtd-spi-nor-stop-passing-around-retlen.patch
@@ -0,0 +1,266 @@
+From 2dd087b16946cf168f401526adf26afa771bb740 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..b2e840d
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-08-mtd-spi-nor-simplify-write-loop.patch
@@ -0,0 +1,103 @@
+From e5d05cbd6d8b01f08c95c427a36c66aac769af4f Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..662c73a
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-09-mtd-spi-nor-add-read-loop.patch
@@ -0,0 +1,54 @@
+From 26f9bcad29a6c240881bd4efc90f16a9990dd6c2 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Tested-by Cyrille Pitchen <cyrille.pitchen at atmel.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..d4f13ec
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.8-10-mtd-m25p80-read-in-spi_max_transfer_size-chunks.patch
@@ -0,0 +1,26 @@
+From 95193796256cfce16e5d881318e15b6b04062c15 Mon Sep 17 00:00:00 2001
+From: Michal Suchanek <hramrach at 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 at gmail.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Acked-by: Michal Suchanek <hramrach at gmail.com>
+Tested-by: Michal Suchanek <hramrach at 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
index 0000000..76a66a3
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/000-4.9-01-spi-introduce-max_message_size-hook-in-spi_master.patch
@@ -0,0 +1,73 @@
+From 5090cc6ae2f79ee779e5faf7c8a28edf42b7d738 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1 at 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 at gmail.com>
+Signed-off-by: Mark Brown <broonie at 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
index 0000000..e902701
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/001-4.11-01-mtd-m25p80-consider-max-message-size-in-m25p80_read.patch
@@ -0,0 +1,30 @@
+From 80a79a889ce5df16c5261ab2f1e8e63b94b78102 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1 at 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 at gmail.com>
+Cc: <stable at vger.kernel.org> # 4.9.x
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen at 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
index 0000000..d806290
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.4/001-4.12-01-spi-bcm63xx-make-spi-subsystem-aware-of-message-size.patch
@@ -0,0 +1,42 @@
+From 3fcc36962c32ad0af2d5904103e2b2b824b6b1aa Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski at 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 at 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];
diff --git a/target/linux/brcm63xx/patches-4.4/202-MTD-DEVICES-m25p80-use-parsers-if-provided-in-flash-.patch b/target/linux/brcm63xx/patches-4.4/202-MTD-DEVICES-m25p80-use-parsers-if-provided-in-flash-.patch
index 6c26d6c..b0c776a 100644
--- a/target/linux/brcm63xx/patches-4.4/202-MTD-DEVICES-m25p80-use-parsers-if-provided-in-flash-.patch
+++ b/target/linux/brcm63xx/patches-4.4/202-MTD-DEVICES-m25p80-use-parsers-if-provided-in-flash-.patch
@@ -11,7 +11,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski at 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
index ddb070c..0000000
--- a/target/linux/brcm63xx/patches-4.4/203-MTD-DEVICES-m25p80-add-support-for-limiting-reads.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 5fb4e8d7287ac8fcb33aae8b1e9e22c5a3c392bd Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <jonas.gorski at 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 at 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 */
- };
-
diff --git a/target/linux/brcm63xx/patches-4.4/411-MIPS-BCM63XX-Register-SPI-flash-if-present.patch b/target/linux/brcm63xx/patches-4.4/411-MIPS-BCM63XX-Register-SPI-flash-if-present.patch
index 0c317cb..1b844fd 100644
--- a/target/linux/brcm63xx/patches-4.4/411-MIPS-BCM63XX-Register-SPI-flash-if-present.patch
+++ b/target/linux/brcm63xx/patches-4.4/411-MIPS-BCM63XX-Register-SPI-flash-if-present.patch
@@ -95,7 +95,7 @@ Signed-off-by: Jonas Gorski <jonas.gorski at 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 at 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:
diff --git a/target/linux/brcm63xx/patches-4.4/414-MTD-m25p80-allow-passing-pp_data.patch b/target/linux/brcm63xx/patches-4.4/414-MTD-m25p80-allow-passing-pp_data.patch
index a0b4b4f..c565ac0 100644
--- a/target/linux/brcm63xx/patches-4.4/414-MTD-m25p80-allow-passing-pp_data.patch
+++ b/target/linux/brcm63xx/patches-4.4/414-MTD-m25p80-allow-passing-pp_data.patch
@@ -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 */
+ };
+
diff --git a/target/linux/brcm63xx/patches-4.4/415-MIPS-BCM63XX-export-the-attached-flash-type.patch b/target/linux/brcm63xx/patches-4.4/415-MIPS-BCM63XX-export-the-attached-flash-type.patch
index d874059..02ecbf7 100644
--- a/target/linux/brcm63xx/patches-4.4/415-MIPS-BCM63XX-export-the-attached-flash-type.patch
+++ b/target/linux/brcm63xx/patches-4.4/415-MIPS-BCM63XX-export-the-attached-flash-type.patch
@@ -11,7 +11,7 @@ Signed-off-by: Jonas Gorski <jogo at 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;
}
}
More information about the lede-commits
mailing list