402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. From acacdac272927ae1d96e0bca51eb82899671eaea Mon Sep 17 00:00:00 2001
  2. From: John Thomson <[email protected]>
  3. Date: Fri, 25 Dec 2020 18:50:08 +1000
  4. Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. Do not prevent writing to mtd partitions where a partition boundary sits
  9. on a minor erasesize boundary.
  10. This addresses a FIXME that has been present since the start of the
  11. linux git history:
  12. /* Doesn't start on a boundary of major erase size */
  13. /* FIXME: Let it be writable if it is on a boundary of
  14. * _minor_ erase size though */
  15. Allow a uniform erase region spi-nor device to be configured
  16. to use the non-uniform erase regions code path for an erase with:
  17. CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
  18. On supporting hardware (SECT_4K: majority of current SPI-NOR device)
  19. provide the facility for an erase to use the least number
  20. of SPI-NOR operations, as well as access to 4K erase without
  21. requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
  22. Introduce erasesize_minor to the mtd struct,
  23. the smallest erasesize supported by the device
  24. On existing devices, this is useful where write support is wanted
  25. for data on a 4K partition, such as some u-boot-env partitions,
  26. or RouterBoot soft_config, while still netting the performance
  27. benefits of using 64K sectors
  28. Performance:
  29. time mtd erase firmware
  30. OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length
  31. Without this patch
  32. MTD_SPI_NOR_USE_4K_SECTORS=y |n
  33. real 2m 11.66s |0m 50.86s
  34. user 0m 0.00s |0m 0.00s
  35. sys 1m 56.20s |0m 50.80s
  36. With this patch
  37. MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y
  38. real 0m 51.68s |0m 50.85s |2m 12.89s
  39. user 0m 0.00s |0m 0.00s |0m 0.01s
  40. sys 0m 46.94s |0m 50.38s |2m 12.46s
  41. Signed-off-by: John Thomson <[email protected]>
  42. Signed-off-by: Thibaut VARÈNE <[email protected]>
  43. ---
  44. checkpatch does not like the printk(KERN_WARNING
  45. these should be changed separately beforehand?
  46. Changes v1 -> v2:
  47. Added mtdcore sysfs for erasesize_minor
  48. Removed finding minor erasesize for variable erase regions device,
  49. as untested and no responses regarding it.
  50. Moved IF_ENABLED for SPINOR variable erase to guard setting
  51. erasesize_minor in spi-nor/core.c
  52. Removed setting erasesize to minor where partition boundaries require
  53. minor erase to be writable
  54. Simplified minor boundary check by relying on minor being a factor of
  55. major
  56. Changes RFC -> v1:
  57. Fix uninitialized variable smatch warning
  58. Reported-by: kernel test robot <[email protected]>
  59. Reported-by: Dan Carpenter <[email protected]>
  60. ---
  61. drivers/mtd/mtdcore.c | 10 ++++++++++
  62. drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++----------
  63. drivers/mtd/spi-nor/Kconfig | 10 ++++++++++
  64. drivers/mtd/spi-nor/core.c | 11 +++++++++--
  65. include/linux/mtd/mtd.h | 2 ++
  66. 5 files changed, 56 insertions(+), 12 deletions(-)
  67. --- a/drivers/mtd/mtdcore.c
  68. +++ b/drivers/mtd/mtdcore.c
  69. @@ -198,6 +198,15 @@ static ssize_t mtd_erasesize_show(struct
  70. }
  71. MTD_DEVICE_ATTR_RO(erasesize);
  72. +static ssize_t mtd_erasesize_minor_show(struct device *dev,
  73. + struct device_attribute *attr, char *buf)
  74. +{
  75. + struct mtd_info *mtd = dev_get_drvdata(dev);
  76. +
  77. + return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor);
  78. +}
  79. +MTD_DEVICE_ATTR_RO(erasesize_minor);
  80. +
  81. static ssize_t mtd_writesize_show(struct device *dev,
  82. struct device_attribute *attr, char *buf)
  83. {
  84. @@ -343,6 +352,7 @@ static struct attribute *mtd_attrs[] = {
  85. &dev_attr_flags.attr,
  86. &dev_attr_size.attr,
  87. &dev_attr_erasesize.attr,
  88. + &dev_attr_erasesize_minor.attr,
  89. &dev_attr_writesize.attr,
  90. &dev_attr_subpagesize.attr,
  91. &dev_attr_oobsize.attr,
  92. --- a/drivers/mtd/mtdpart.c
  93. +++ b/drivers/mtd/mtdpart.c
  94. @@ -47,6 +47,7 @@ static struct mtd_info *allocate_partiti
  95. struct mtd_info *master = mtd_get_master(parent);
  96. int wr_alignment = (parent->flags & MTD_NO_ERASE) ?
  97. master->writesize : master->erasesize;
  98. + int wr_alignment_minor = 0;
  99. u64 parent_size = mtd_is_partition(parent) ?
  100. parent->part.size : parent->size;
  101. struct mtd_info *child;
  102. @@ -171,6 +172,7 @@ static struct mtd_info *allocate_partiti
  103. } else {
  104. /* Single erase size */
  105. child->erasesize = master->erasesize;
  106. + child->erasesize_minor = master->erasesize_minor;
  107. }
  108. /*
  109. @@ -178,26 +180,39 @@ static struct mtd_info *allocate_partiti
  110. * exposes several regions with different erasesize. Adjust
  111. * wr_alignment accordingly.
  112. */
  113. - if (!(child->flags & MTD_NO_ERASE))
  114. + if (!(child->flags & MTD_NO_ERASE)) {
  115. wr_alignment = child->erasesize;
  116. + wr_alignment_minor = child->erasesize_minor;
  117. + }
  118. tmp = mtd_get_master_ofs(child, 0);
  119. remainder = do_div(tmp, wr_alignment);
  120. if ((child->flags & MTD_WRITEABLE) && remainder) {
  121. - /* Doesn't start on a boundary of major erase size */
  122. - /* FIXME: Let it be writable if it is on a boundary of
  123. - * _minor_ erase size though */
  124. - child->flags &= ~MTD_WRITEABLE;
  125. - printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
  126. - part->name);
  127. + if (wr_alignment_minor) {
  128. + /* rely on minor being a factor of major erasesize */
  129. + tmp = remainder;
  130. + remainder = do_div(tmp, wr_alignment_minor);
  131. + }
  132. + if (remainder) {
  133. + child->flags &= ~MTD_WRITEABLE;
  134. + printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
  135. + part->name);
  136. + }
  137. }
  138. tmp = mtd_get_master_ofs(child, 0) + child->part.size;
  139. remainder = do_div(tmp, wr_alignment);
  140. if ((child->flags & MTD_WRITEABLE) && remainder) {
  141. - child->flags &= ~MTD_WRITEABLE;
  142. - printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
  143. - part->name);
  144. + if (wr_alignment_minor) {
  145. + tmp = remainder;
  146. + remainder = do_div(tmp, wr_alignment_minor);
  147. + }
  148. +
  149. + if (remainder) {
  150. + child->flags &= ~MTD_WRITEABLE;
  151. + printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
  152. + part->name);
  153. + }
  154. }
  155. child->size = child->part.size;
  156. --- a/drivers/mtd/spi-nor/Kconfig
  157. +++ b/drivers/mtd/spi-nor/Kconfig
  158. @@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR
  159. if MTD_SPI_NOR
  160. +config MTD_SPI_NOR_USE_VARIABLE_ERASE
  161. + bool "Disable uniform_erase to allow use of all hardware supported erasesizes"
  162. + depends on !MTD_SPI_NOR_USE_4K_SECTORS
  163. + default n
  164. + help
  165. + Allow mixed use of all hardware supported erasesizes,
  166. + by forcing spi_nor to use the multiple eraseregions code path.
  167. + For example: A 68K erase will use one 64K erase, and one 4K erase
  168. + on supporting hardware.
  169. +
  170. config MTD_SPI_NOR_USE_4K_SECTORS
  171. bool "Use small 4096 B erase sectors"
  172. default y
  173. --- a/drivers/mtd/spi-nor/core.c
  174. +++ b/drivers/mtd/spi-nor/core.c
  175. @@ -1150,6 +1150,8 @@ static u8 spi_nor_convert_3to4_erase(u8
  176. static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
  177. {
  178. + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE))
  179. + return false;
  180. return !!nor->params->erase_map.uniform_erase_type;
  181. }
  182. @@ -2582,6 +2584,7 @@ static int spi_nor_select_erase(struct s
  183. {
  184. struct spi_nor_erase_map *map = &nor->params->erase_map;
  185. const struct spi_nor_erase_type *erase = NULL;
  186. + const struct spi_nor_erase_type *erase_minor = NULL;
  187. struct mtd_info *mtd = &nor->mtd;
  188. u32 wanted_size = nor->info->sector_size;
  189. int i;
  190. @@ -2614,8 +2617,9 @@ static int spi_nor_select_erase(struct s
  191. */
  192. for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
  193. if (map->erase_type[i].size) {
  194. - erase = &map->erase_type[i];
  195. - break;
  196. + if (!erase)
  197. + erase = &map->erase_type[i];
  198. + erase_minor = &map->erase_type[i];
  199. }
  200. }
  201. @@ -2623,6 +2627,9 @@ static int spi_nor_select_erase(struct s
  202. return -EINVAL;
  203. mtd->erasesize = erase->size;
  204. + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) &&
  205. + erase_minor && erase_minor->size < erase->size)
  206. + mtd->erasesize_minor = erase_minor->size;
  207. return 0;
  208. }
  209. --- a/include/linux/mtd/mtd.h
  210. +++ b/include/linux/mtd/mtd.h
  211. @@ -245,6 +245,8 @@ struct mtd_info {
  212. * information below if they desire
  213. */
  214. uint32_t erasesize;
  215. + /* "Minor" (smallest) erase size supported by the whole device */
  216. + uint32_t erasesize_minor;
  217. /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
  218. * though individual bits can be cleared), in case of NAND flash it is
  219. * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR