kernel: bump 5.10 to 5.10.20
[openwrt/staging/rmilecki.git] / target / linux / generic / pending-5.10 / 481-mtd-spi-nor-rework-broken-flash-reset-support.patch
1 From ea92cbb50a78404e29de2cc3999a240615ffb1c8 Mon Sep 17 00:00:00 2001
2 From: Chuanhong Guo <gch981213@gmail.com>
3 Date: Mon, 6 Apr 2020 17:58:48 +0800
4 Subject: [PATCH] mtd: spi-nor: rework broken-flash-reset support
5
6 Instead of resetting flash to 3B address on remove hook, this
7 implementation only enters 4B mode when needed, which prevents
8 more unexpected reboot stuck. This implementation makes it only
9 break when a kernel panic happens during flash operation on 16M+
10 areas.
11 *OpenWrt only*: silent broken-flash-reset warning. We are not dealing
12 with vendors and it's unpleasant for users to se that unnecessary
13 and long WARN_ON print.
14
15 Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
16 ---
17 drivers/mtd/spi-nor/spi-nor.c | 52 +++++++++++++++++++++++++++++++++--
18 1 file changed, 49 insertions(+), 3 deletions(-)
19
20 --- a/drivers/mtd/spi-nor/core.c
21 +++ b/drivers/mtd/spi-nor/core.c
22 @@ -1447,6 +1447,23 @@ destroy_erase_cmd_list:
23 return ret;
24 }
25
26 +int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr)
27 +{
28 + u8 addr_width;
29 +
30 + if ((nor->flags & (SNOR_F_4B_OPCODES | SNOR_F_BROKEN_RESET)) !=
31 + SNOR_F_BROKEN_RESET)
32 + return 0;
33 +
34 + addr_width = addr & 0xff000000 ? 4 : 3;
35 + if (nor->addr_width == addr_width)
36 + return 0;
37 +
38 + nor->addr_width = addr_width;
39 +
40 + return nor->params->set_4byte_addr_mode(nor, addr_width == 4);
41 +}
42 +
43 /*
44 * Erase an address range on the nor chip. The address range may extend
45 * one or more erase sectors. Return an error is there is a problem erasing.
46 @@ -1474,6 +1491,10 @@ static int spi_nor_erase(struct mtd_info
47 if (ret)
48 return ret;
49
50 + ret = spi_nor_check_set_addr_width(nor, instr->addr + instr->len);
51 + if (ret < 0)
52 + return ret;
53 +
54 /* whole-chip erase? */
55 if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
56 unsigned long timeout;
57 @@ -1533,6 +1554,7 @@ static int spi_nor_erase(struct mtd_info
58 ret = spi_nor_write_disable(nor);
59
60 erase_err:
61 + spi_nor_check_set_addr_width(nor, 0);
62 spi_nor_unlock_and_unprep(nor);
63
64 return ret;
65 @@ -1872,7 +1894,9 @@ static int spi_nor_lock(struct mtd_info
66 if (ret)
67 return ret;
68
69 + spi_nor_check_set_addr_width(nor, ofs + len);
70 ret = nor->params->locking_ops->lock(nor, ofs, len);
71 + spi_nor_check_set_addr_width(nor, 0);
72
73 spi_nor_unlock_and_unprep(nor);
74 return ret;
75 @@ -1887,7 +1911,9 @@ static int spi_nor_unlock(struct mtd_inf
76 if (ret)
77 return ret;
78
79 + spi_nor_check_set_addr_width(nor, ofs + len);
80 ret = nor->params->locking_ops->unlock(nor, ofs, len);
81 + spi_nor_check_set_addr_width(nor, 0);
82
83 spi_nor_unlock_and_unprep(nor);
84 return ret;
85 @@ -1902,7 +1928,9 @@ static int spi_nor_is_locked(struct mtd_
86 if (ret)
87 return ret;
88
89 + spi_nor_check_set_addr_width(nor, ofs + len);
90 ret = nor->params->locking_ops->is_locked(nor, ofs, len);
91 + spi_nor_check_set_addr_width(nor, 0);
92
93 spi_nor_unlock_and_unprep(nor);
94 return ret;
95 @@ -2095,6 +2123,10 @@ static int spi_nor_read(struct mtd_info
96 if (ret)
97 return ret;
98
99 + ret = spi_nor_check_set_addr_width(nor, from + len);
100 + if (ret < 0)
101 + return ret;
102 +
103 while (len) {
104 loff_t addr = from;
105
106 @@ -2118,6 +2150,7 @@ static int spi_nor_read(struct mtd_info
107 ret = 0;
108
109 read_err:
110 + spi_nor_check_set_addr_width(nor, 0);
111 spi_nor_unlock_and_unprep(nor);
112 return ret;
113 }
114 @@ -2140,6 +2173,10 @@ static int spi_nor_write(struct mtd_info
115 if (ret)
116 return ret;
117
118 + ret = spi_nor_check_set_addr_width(nor, to + len);
119 + if (ret < 0)
120 + return ret;
121 +
122 for (i = 0; i < len; ) {
123 ssize_t written;
124 loff_t addr = to + i;
125 @@ -2182,6 +2219,7 @@ static int spi_nor_write(struct mtd_info
126 }
127
128 write_err:
129 + spi_nor_check_set_addr_width(nor, 0);
130 spi_nor_unlock_and_unprep(nor);
131 return ret;
132 }
133 @@ -2977,9 +3015,13 @@ static int spi_nor_init(struct spi_nor *
134 * reboots (e.g., crashes). Warn the user (or hopefully, system
135 * designer) that this is bad.
136 */
137 - WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
138 - "enabling reset hack; may not recover from unexpected reboots\n");
139 - nor->params->set_4byte_addr_mode(nor, true);
140 + if (nor->flags & SNOR_F_BROKEN_RESET) {
141 + dev_warn(nor->dev,
142 + "enabling reset hack; may not recover from unexpected reboots\n");
143 + nor->addr_width = 3;
144 + } else {
145 + nor->params->set_4byte_addr_mode(nor, true);
146 + }
147 }
148
149 return 0;
150 --- a/drivers/mtd/spi-nor/core.h
151 +++ b/drivers/mtd/spi-nor/core.h
152 @@ -400,6 +400,7 @@ extern const struct spi_nor_manufacturer
153 extern const struct spi_nor_manufacturer spi_nor_xmc;
154 extern const struct spi_nor_manufacturer spi_nor_xtx;
155
156 +int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr);
157 int spi_nor_write_enable(struct spi_nor *nor);
158 int spi_nor_write_disable(struct spi_nor *nor);
159 int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable);
160 --- a/drivers/mtd/spi-nor/sst.c
161 +++ b/drivers/mtd/spi-nor/sst.c
162 @@ -55,6 +55,10 @@ static int sst_write(struct mtd_info *mt
163 if (ret)
164 return ret;
165
166 + ret = spi_nor_check_set_addr_width(nor, to + len);
167 + if (ret < 0)
168 + return ret;
169 +
170 ret = spi_nor_write_enable(nor);
171 if (ret)
172 goto out;
173 @@ -124,6 +128,7 @@ static int sst_write(struct mtd_info *mt
174 }
175 out:
176 *retlen += actual;
177 + spi_nor_check_set_addr_width(nor, 0);
178 spi_nor_unlock_and_unprep(nor);
179 return ret;
180 }