From 2a2b16210bbc8c5881286d2ff742f3bdf1a7fd9c Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Tue, 7 Feb 2017 12:01:46 +0100 Subject: [PATCH] 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 --- ...pose-master-transfer-size-limitation.patch | 51 ++++ ...or-change-return-value-of-read-write.patch | 149 ++++++++++ ...n-amount-of-data-transferred-or-erro.patch | 91 ++++++ ...return-amount-of-data-read-written-o.patch | 72 +++++ ...turn-amount-of-data-transferred-or-e.patch | 51 ++++ ...pi-nor-check-return-value-from-write.patch | 118 ++++++++ ...d-spi-nor-stop-passing-around-retlen.patch | 266 ++++++++++++++++++ ...8-08-mtd-spi-nor-simplify-write-loop.patch | 103 +++++++ ...000-4.8-09-mtd-spi-nor-add-read-loop.patch | 54 ++++ ...read-in-spi_max_transfer_size-chunks.patch | 26 ++ ...-max_message_size-hook-in-spi_master.patch | 73 +++++ ...ider-max-message-size-in-m25p80_read.patch | 30 ++ ...-spi-subsystem-aware-of-message-size.patch | 42 +++ ...80-use-parsers-if-provided-in-flash-.patch | 2 +- ...25p80-add-support-for-limiting-reads.patch | 90 ------ ...CM63XX-Register-SPI-flash-if-present.patch | 5 +- ...414-MTD-m25p80-allow-passing-pp_data.patch | 12 +- ...M63XX-export-the-attached-flash-type.patch | 2 +- 18 files changed, 1135 insertions(+), 102 deletions(-) create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.5-20-spi-expose-master-transfer-size-limitation.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-01-mtd-spi-nor-change-return-value-of-read-write.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-02-mtd-m25p80-return-amount-of-data-transferred-or-erro.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-03-mtd-fsl-quadspi-return-amount-of-data-read-written-o.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-05-mtd-nxp-spifi-return-amount-of-data-transferred-or-e.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-06-mtd-spi-nor-check-return-value-from-write.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-07-mtd-spi-nor-stop-passing-around-retlen.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-08-mtd-spi-nor-simplify-write-loop.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-09-mtd-spi-nor-add-read-loop.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.8-10-mtd-m25p80-read-in-spi_max_transfer_size-chunks.patch create mode 100644 target/linux/brcm63xx/patches-4.4/000-4.9-01-spi-introduce-max_message_size-hook-in-spi_master.patch create mode 100644 target/linux/brcm63xx/patches-4.4/001-4.11-01-mtd-m25p80-consider-max-message-size-in-m25p80_read.patch create mode 100644 target/linux/brcm63xx/patches-4.4/001-4.12-01-spi-bcm63xx-make-spi-subsystem-aware-of-message-size.patch delete mode 100644 target/linux/brcm63xx/patches-4.4/203-MTD-DEVICES-m25p80-add-support-for-limiting-reads.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 index 0000000000..21e037ce77 --- /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 +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 +Signed-off-by: Mark Brown +--- + 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 0000000000..31c24e51a1 --- /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 +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 +Signed-off-by: Brian Norris +Tested-by Cyrille Pitchen +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..fb89b77072 --- /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 +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 +Signed-off-by: Brian Norris +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..232f11cf0d --- /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 +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 +Signed-off-by: Brian Norris +--- + 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 0000000000..0458148399 --- /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 +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 +--- + 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 0000000000..0bdcccfdf6 --- /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 +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 +Signed-off-by: Brian Norris +Tested-by Cyrille Pitchen +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..9949d35a6f --- /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 +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 +Signed-off-by: Brian Norris +Tested-by Cyrille Pitchen +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..b2e840d488 --- /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 +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 +Signed-off-by: Brian Norris +Tested-by Cyrille Pitchen +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..662c73ada9 --- /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 +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 +Signed-off-by: Brian Norris +Tested-by Cyrille Pitchen +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..d4f13ecea8 --- /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 +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 +Signed-off-by: Brian Norris +Acked-by: Michal Suchanek +Tested-by: Michal Suchanek +--- + 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 0000000000..76a66a3bb7 --- /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 +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 +Signed-off-by: Mark Brown +--- + 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 0000000000..e90270156e --- /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 +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 +Cc: # 4.9.x +Signed-off-by: Cyrille Pitchen +--- + 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 0000000000..d806290fd1 --- /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 +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 +--- + 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 6c26d6cd41..b0c776a9a3 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 --- 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 ddb070c988..0000000000 --- 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 -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 ---- - 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 0c317cb1b2..1b844fd7d5 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 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 + 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 a0b4b4ff36..c565ac0210 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 d874059410..02ecbf7347 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 --- 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; } } -- 2.30.2