Skip to content

Commit 1181385

Browse files
committed
mtd: spi-nand: macronix: Continuous read support
Enabling continuous read support implies several changes which must be done atomically in order to keep the code base consistent and bisectable. 1/ Retrieving bitflips differently Improve the helper retrieving the number of bitflips to support the case where many pages have been read instead of just one. In this case, if there is one page with bitflips, we cannot know the detail and just get the information of the maximum number of bitflips corrected in the most corrupted chunk. Compatible Macronix flashes return: - the ECC status for the last page read (bits 0-3), - the amount of bitflips for the whole read operation (bits 4-7). Hence, when reading two consecutive pages, if there was 2 bits corrected at most in one chunk, we return this amount times (arbitrary) the number read pages. It is probably a very pessimistic calculation in most cases, but still less pessimistic than if we multiplied this amount by the number of chunks. Anyway, this is just for statistics, the important data is the maximum amount of bitflips, which leads to wear leveling. 2/ Configuring, enabling and disabling the feature Create an init function for allocating a vendor structure. Use this vendor structure to cache the internal continuous read state. The state is being used to discriminate between the two bitflips retrieval methods. Finally, helpers for enabling and disabling sequential reads are also created. 3/ Fill the chips table Flag all the chips supporting the feature with the ->set_cont_read() helper. In order to validate the changes, I modified the mtd-utils test suite with extended versions of nandbiterrs, nanddump and flash_speed in order to support, test and benchmark continuous reads. I also ran all the UBI tests successfully. The nandbiterrs tool allows to track the ECC efficiency and feedback. Here is its default output (stripped): Successfully corrected 0 bit errors per subpage Read reported 1 corrected bit errors Successfully corrected 1 bit errors per subpage Read reported 2 corrected bit errors Successfully corrected 2 bit errors per subpage Read reported 3 corrected bit errors Successfully corrected 3 bit errors per subpage Read reported 4 corrected bit errors Successfully corrected 4 bit errors per subpage Read reported 5 corrected bit errors Successfully corrected 5 bit errors per subpage Read reported 6 corrected bit errors Successfully corrected 6 bit errors per subpage Read reported 7 corrected bit errors Successfully corrected 7 bit errors per subpage Read reported 8 corrected bit errors Successfully corrected 8 bit errors per subpage Failed to recover 1 bitflips Read error after 9 bit errors per page The output using the continuous option over two pages (the second page is kept intact): Successfully corrected 0 bit errors per subpage Read reported 2 corrected bit errors Successfully corrected 1 bit errors per subpage Read reported 4 corrected bit errors Successfully corrected 2 bit errors per subpage Read reported 6 corrected bit errors Successfully corrected 3 bit errors per subpage Read reported 8 corrected bit errors Successfully corrected 4 bit errors per subpage Read reported 10 corrected bit errors Successfully corrected 5 bit errors per subpage Read reported 12 corrected bit errors Successfully corrected 6 bit errors per subpage Read reported 14 corrected bit errors Successfully corrected 7 bit errors per subpage Read reported 16 corrected bit errors Successfully corrected 8 bit errors per subpage Failed to recover 1 bitflips Read error after 9 bit errors per page Regarding the throughput improvements, tests have been conducted in 1-1-1 and 1-1-4 modes, reading a full block X pages at a time, X ranging from 1 to 64 (size of a block with the tested device). The percent value on the right is the comparison of the same test conducted without the continuous read feature, ie. reading X pages in one single user request, which got naturally split by the core whit the continuous read optimization disabled into single-page reads. * 1-1-1 result: 1 page read speed is 2634 KiB/s 2 page read speed is 2704 KiB/s (+3%) 3 page read speed is 2747 KiB/s (+5%) 4 page read speed is 2804 KiB/s (+7%) 5 page read speed is 2782 KiB/s 6 page read speed is 2826 KiB/s 7 page read speed is 2834 KiB/s 8 page read speed is 2821 KiB/s 9 page read speed is 2846 KiB/s 10 page read speed is 2819 KiB/s 11 page read speed is 2871 KiB/s (+10%) 12 page read speed is 2823 KiB/s 13 page read speed is 2880 KiB/s 14 page read speed is 2842 KiB/s 15 page read speed is 2862 KiB/s 16 page read speed is 2837 KiB/s 32 page read speed is 2879 KiB/s 64 page read speed is 2842 KiB/s * 1-1-4 result: 1 page read speed is 7562 KiB/s 2 page read speed is 8904 KiB/s (+15%) 3 page read speed is 9655 KiB/s (+25%) 4 page read speed is 10118 KiB/s (+30%) 5 page read speed is 10084 KiB/s 6 page read speed is 10300 KiB/s 7 page read speed is 10434 KiB/s (+35%) 8 page read speed is 10406 KiB/s 9 page read speed is 10769 KiB/s (+40%) 10 page read speed is 10666 KiB/s 11 page read speed is 10757 KiB/s 12 page read speed is 10835 KiB/s 13 page read speed is 10976 KiB/s 14 page read speed is 11200 KiB/s 15 page read speed is 11009 KiB/s 16 page read speed is 11082 KiB/s 32 page read speed is 11352 KiB/s (+45%) 64 page read speed is 11403 KiB/s This work has received support and could be achieved thanks to Alvin Zhou <[email protected]>. Signed-off-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/linux-mtd/[email protected]
1 parent e1f251e commit 1181385

File tree

1 file changed

+86
-29
lines changed

1 file changed

+86
-29
lines changed

drivers/mtd/nand/spi/macronix.c

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,26 @@
55
* Author: Boris Brezillon <[email protected]>
66
*/
77

8+
#include <linux/bitfield.h>
89
#include <linux/device.h>
910
#include <linux/kernel.h>
1011
#include <linux/mtd/spinand.h>
1112

1213
#define SPINAND_MFR_MACRONIX 0xC2
13-
#define MACRONIX_ECCSR_MASK 0x0F
14+
#define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr)
15+
#define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr)
16+
#define MACRONIX_CFG_CONT_READ BIT(2)
1417

1518
#define STATUS_ECC_HAS_BITFLIPS_THRESHOLD (3 << 4)
1619

20+
/* Bitflip theshold configuration register */
21+
#define REG_CFG_BFT 0x10
22+
#define CFG_BFT(x) FIELD_PREP(GENMASK(7, 4), (x))
23+
24+
struct macronix_priv {
25+
bool cont_read;
26+
};
27+
1728
static SPINAND_OP_VARIANTS(read_cache_variants,
1829
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
1930
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -53,6 +64,7 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
5364

5465
static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
5566
{
67+
struct macronix_priv *priv = spinand->priv;
5668
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
5769
SPI_MEM_OP_NO_ADDR,
5870
SPI_MEM_OP_DUMMY(1, 1),
@@ -62,33 +74,25 @@ static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
6274
if (ret)
6375
return ret;
6476

65-
*eccsr &= MACRONIX_ECCSR_MASK;
66-
return 0;
67-
}
68-
69-
static int macronix_get_bf(struct spinand_device *spinand, u8 status)
70-
{
71-
struct nand_device *nand = spinand_to_nand(spinand);
72-
u8 eccsr;
73-
7477
/*
75-
* Let's try to retrieve the real maximum number of bitflips
76-
* in order to avoid forcing the wear-leveling layer to move
77-
* data around if it's not necessary.
78+
* ECCSR exposes the number of bitflips for the last read page in bits [3:0].
79+
* Continuous read compatible chips also expose the maximum number of
80+
* bitflips for the whole (continuous) read operation in bits [7:4].
7881
*/
79-
if (macronix_get_eccsr(spinand, spinand->scratchbuf))
80-
return nanddev_get_ecc_conf(nand)->strength;
81-
82-
eccsr = *spinand->scratchbuf;
83-
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || !eccsr))
84-
return nanddev_get_ecc_conf(nand)->strength;
82+
if (!priv->cont_read)
83+
*eccsr = MACRONIX_ECCSR_BF_LAST_PAGE(*eccsr);
84+
else
85+
*eccsr = MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(*eccsr);
8586

86-
return eccsr;
87+
return 0;
8788
}
8889

8990
static int macronix_ecc_get_status(struct spinand_device *spinand,
9091
u8 status)
9192
{
93+
struct nand_device *nand = spinand_to_nand(spinand);
94+
u8 eccsr;
95+
9296
switch (status & STATUS_ECC_MASK) {
9397
case STATUS_ECC_NO_BITFLIPS:
9498
return 0;
@@ -97,15 +101,41 @@ static int macronix_ecc_get_status(struct spinand_device *spinand,
97101
return -EBADMSG;
98102

99103
case STATUS_ECC_HAS_BITFLIPS:
100-
case STATUS_ECC_HAS_BITFLIPS_THRESHOLD:
101-
return macronix_get_bf(spinand, status);
104+
/*
105+
* Let's try to retrieve the real maximum number of bitflips
106+
* in order to avoid forcing the wear-leveling layer to move
107+
* data around if it's not necessary.
108+
*/
109+
if (macronix_get_eccsr(spinand, spinand->scratchbuf))
110+
return nanddev_get_ecc_conf(nand)->strength;
111+
112+
eccsr = *spinand->scratchbuf;
113+
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || !eccsr))
114+
return nanddev_get_ecc_conf(nand)->strength;
115+
116+
return eccsr;
102117
default:
103118
break;
104119
}
105120

106121
return -EINVAL;
107122
}
108123

124+
static int macronix_set_cont_read(struct spinand_device *spinand, bool enable)
125+
{
126+
struct macronix_priv *priv = spinand->priv;
127+
int ret;
128+
129+
ret = spinand_upd_cfg(spinand, MACRONIX_CFG_CONT_READ,
130+
enable ? MACRONIX_CFG_CONT_READ : 0);
131+
if (ret)
132+
return ret;
133+
134+
priv->cont_read = enable;
135+
136+
return 0;
137+
}
138+
109139
static const struct spinand_info macronix_spinand_table[] = {
110140
SPINAND_INFO("MX35LF1GE4AB",
111141
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
@@ -135,7 +165,8 @@ static const struct spinand_info macronix_spinand_table[] = {
135165
&update_cache_variants),
136166
SPINAND_HAS_QE_BIT,
137167
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
138-
macronix_ecc_get_status)),
168+
macronix_ecc_get_status),
169+
SPINAND_CONT_READ(macronix_set_cont_read)),
139170
SPINAND_INFO("MX35LF4GE4AD",
140171
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03),
141172
NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
@@ -145,7 +176,8 @@ static const struct spinand_info macronix_spinand_table[] = {
145176
&update_cache_variants),
146177
SPINAND_HAS_QE_BIT,
147178
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
148-
macronix_ecc_get_status)),
179+
macronix_ecc_get_status),
180+
SPINAND_CONT_READ(macronix_set_cont_read)),
149181
SPINAND_INFO("MX35LF1G24AD",
150182
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03),
151183
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
@@ -251,7 +283,8 @@ static const struct spinand_info macronix_spinand_table[] = {
251283
&update_cache_variants),
252284
SPINAND_HAS_QE_BIT,
253285
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
254-
macronix_ecc_get_status)),
286+
macronix_ecc_get_status),
287+
SPINAND_CONT_READ(macronix_set_cont_read)),
255288
SPINAND_INFO("MX35UF2G14AC",
256289
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
257290
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
@@ -291,7 +324,8 @@ static const struct spinand_info macronix_spinand_table[] = {
291324
&update_cache_variants),
292325
SPINAND_HAS_QE_BIT,
293326
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
294-
macronix_ecc_get_status)),
327+
macronix_ecc_get_status),
328+
SPINAND_CONT_READ(macronix_set_cont_read)),
295329
SPINAND_INFO("MX35UF2GE4AC",
296330
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2, 0x01),
297331
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
@@ -301,7 +335,8 @@ static const struct spinand_info macronix_spinand_table[] = {
301335
&update_cache_variants),
302336
SPINAND_HAS_QE_BIT,
303337
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
304-
macronix_ecc_get_status)),
338+
macronix_ecc_get_status),
339+
SPINAND_CONT_READ(macronix_set_cont_read)),
305340
SPINAND_INFO("MX35UF1G14AC",
306341
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
307342
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
@@ -331,7 +366,8 @@ static const struct spinand_info macronix_spinand_table[] = {
331366
&update_cache_variants),
332367
SPINAND_HAS_QE_BIT,
333368
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
334-
macronix_ecc_get_status)),
369+
macronix_ecc_get_status),
370+
SPINAND_CONT_READ(macronix_set_cont_read)),
335371
SPINAND_INFO("MX35UF1GE4AC",
336372
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92, 0x01),
337373
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
@@ -341,7 +377,8 @@ static const struct spinand_info macronix_spinand_table[] = {
341377
&update_cache_variants),
342378
SPINAND_HAS_QE_BIT,
343379
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
344-
macronix_ecc_get_status)),
380+
macronix_ecc_get_status),
381+
SPINAND_CONT_READ(macronix_set_cont_read)),
345382
SPINAND_INFO("MX31LF2GE4BC",
346383
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2e),
347384
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
@@ -364,7 +401,27 @@ static const struct spinand_info macronix_spinand_table[] = {
364401
macronix_ecc_get_status)),
365402
};
366403

404+
static int macronix_spinand_init(struct spinand_device *spinand)
405+
{
406+
struct macronix_priv *priv;
407+
408+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
409+
if (!priv)
410+
return -ENOMEM;
411+
412+
spinand->priv = priv;
413+
414+
return 0;
415+
}
416+
417+
static void macronix_spinand_cleanup(struct spinand_device *spinand)
418+
{
419+
kfree(spinand->priv);
420+
}
421+
367422
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
423+
.init = macronix_spinand_init,
424+
.cleanup = macronix_spinand_cleanup,
368425
};
369426

370427
const struct spinand_manufacturer macronix_spinand_manufacturer = {

0 commit comments

Comments
 (0)