Skip to content

Commit 0473d5b

Browse files
committed
Merge tag 'spi-nor/for-6.18' into mtd/next
SPI NOR changes for 6.18 Notable changes: - Some flashes can't perform reads or writes with start or end being an odd number in Octal DTR mode. File systems like UBIFS can request such reads or writes, causing the transaction to error out. Pad the read or write transactions with extra bytes to avoid this problem. Signed-off-by: Miquel Raynal <[email protected]>
2 parents 362f84c + 17926cd commit 0473d5b

File tree

1 file changed

+143
-2
lines changed

1 file changed

+143
-2
lines changed

drivers/mtd/spi-nor/core.c

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,76 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
20142014
return info;
20152015
}
20162016

2017+
/*
2018+
* On Octal DTR capable flashes, reads cannot start or end at an odd
2019+
* address in Octal DTR mode. Extra bytes need to be read at the start
2020+
* or end to make sure both the start address and length remain even.
2021+
*/
2022+
static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len,
2023+
u_char *buf)
2024+
{
2025+
u_char *tmp_buf;
2026+
size_t tmp_len;
2027+
loff_t start, end;
2028+
int ret, bytes_read;
2029+
2030+
if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2))
2031+
return spi_nor_read_data(nor, from, len, buf);
2032+
else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE)
2033+
return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE),
2034+
buf);
2035+
2036+
tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2037+
if (!tmp_buf)
2038+
return -ENOMEM;
2039+
2040+
start = round_down(from, 2);
2041+
end = round_up(from + len, 2);
2042+
2043+
/*
2044+
* Avoid allocating too much memory. The requested read length might be
2045+
* quite large. Allocating a buffer just as large (slightly bigger, in
2046+
* fact) would put unnecessary memory pressure on the system.
2047+
*
2048+
* For example if the read is from 3 to 1M, then this will read from 2
2049+
* to 4098. The reads from 4098 to 1M will then not need a temporary
2050+
* buffer so they can proceed as normal.
2051+
*/
2052+
tmp_len = min_t(size_t, end - start, PAGE_SIZE);
2053+
2054+
ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf);
2055+
if (ret == 0) {
2056+
ret = -EIO;
2057+
goto out;
2058+
}
2059+
if (ret < 0)
2060+
goto out;
2061+
2062+
/*
2063+
* More bytes are read than actually requested, but that number can't be
2064+
* reported to the calling function or it will confuse its calculations.
2065+
* Calculate how many of the _requested_ bytes were read.
2066+
*/
2067+
bytes_read = ret;
2068+
2069+
if (from != start)
2070+
ret -= from - start;
2071+
2072+
/*
2073+
* Only account for extra bytes at the end if they were actually read.
2074+
* For example, if the total length was truncated because of temporary
2075+
* buffer size limit then the adjustment for the extra bytes at the end
2076+
* is not needed.
2077+
*/
2078+
if (start + bytes_read == end)
2079+
ret -= end - (from + len);
2080+
2081+
memcpy(buf, tmp_buf + (from - start), ret);
2082+
out:
2083+
kfree(tmp_buf);
2084+
return ret;
2085+
}
2086+
20172087
static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
20182088
size_t *retlen, u_char *buf)
20192089
{
@@ -2031,7 +2101,11 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
20312101
while (len) {
20322102
loff_t addr = from;
20332103

2034-
ret = spi_nor_read_data(nor, addr, len, buf);
2104+
if (nor->read_proto == SNOR_PROTO_8_8_8_DTR)
2105+
ret = spi_nor_octal_dtr_read(nor, addr, len, buf);
2106+
else
2107+
ret = spi_nor_read_data(nor, addr, len, buf);
2108+
20352109
if (ret == 0) {
20362110
/* We shouldn't see 0-length reads */
20372111
ret = -EIO;
@@ -2054,6 +2128,68 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
20542128
return ret;
20552129
}
20562130

2131+
/*
2132+
* On Octal DTR capable flashes, writes cannot start or end at an odd address
2133+
* in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to
2134+
* make sure the start address and end address are even. 0xff is used because
2135+
* on NOR flashes a program operation can only flip bits from 1 to 0, not the
2136+
* other way round. 0 to 1 flip needs to happen via erases.
2137+
*/
2138+
static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len,
2139+
const u8 *buf)
2140+
{
2141+
u8 *tmp_buf;
2142+
size_t bytes_written;
2143+
loff_t start, end;
2144+
int ret;
2145+
2146+
if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2))
2147+
return spi_nor_write_data(nor, to, len, buf);
2148+
2149+
tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL);
2150+
if (!tmp_buf)
2151+
return -ENOMEM;
2152+
2153+
memset(tmp_buf, 0xff, nor->params->page_size);
2154+
2155+
start = round_down(to, 2);
2156+
end = round_up(to + len, 2);
2157+
2158+
memcpy(tmp_buf + (to - start), buf, len);
2159+
2160+
ret = spi_nor_write_data(nor, start, end - start, tmp_buf);
2161+
if (ret == 0) {
2162+
ret = -EIO;
2163+
goto out;
2164+
}
2165+
if (ret < 0)
2166+
goto out;
2167+
2168+
/*
2169+
* More bytes are written than actually requested, but that number can't
2170+
* be reported to the calling function or it will confuse its
2171+
* calculations. Calculate how many of the _requested_ bytes were
2172+
* written.
2173+
*/
2174+
bytes_written = ret;
2175+
2176+
if (to != start)
2177+
ret -= to - start;
2178+
2179+
/*
2180+
* Only account for extra bytes at the end if they were actually
2181+
* written. For example, if for some reason the controller could only
2182+
* complete a partial write then the adjustment for the extra bytes at
2183+
* the end is not needed.
2184+
*/
2185+
if (start + bytes_written == end)
2186+
ret -= end - (to + len);
2187+
2188+
out:
2189+
kfree(tmp_buf);
2190+
return ret;
2191+
}
2192+
20572193
/*
20582194
* Write an address range to the nor chip. Data must be written in
20592195
* FLASH_PAGESIZE chunks. The address range may be any size provided
@@ -2090,7 +2226,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
20902226
goto write_err;
20912227
}
20922228

2093-
ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
2229+
if (nor->write_proto == SNOR_PROTO_8_8_8_DTR)
2230+
ret = spi_nor_octal_dtr_write(nor, addr, page_remain,
2231+
buf + i);
2232+
else
2233+
ret = spi_nor_write_data(nor, addr, page_remain,
2234+
buf + i);
20942235
spi_nor_unlock_device(nor);
20952236
if (ret < 0)
20962237
goto write_err;

0 commit comments

Comments
 (0)