Skip to content

Commit a78f007

Browse files
committed
kernel: QCOM SPI NAND: backport multiple fixes
These patches fix bugs in a patch we backported. These patch were cherry picked from upstream Linux because it references a patch we backported in the fixes tag. The patches were reordered to match the ordering in the upstream Linux kernel. Fixes: 93173ae ("qualcommbe: ipq95xx: Add initial support for new target") Link: openwrt/openwrt#21366 (cherry picked from commit 5230157) Link: openwrt/openwrt#21390 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
1 parent 236149c commit a78f007

13 files changed

+441
-6
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
From 36c6468724aa98d33fea9a1d7e07ddda6302f5d4 Mon Sep 17 00:00:00 2001
2+
From: Geert Uytterhoeven <geert+renesas@glider.be>
3+
Date: Fri, 28 Mar 2025 09:24:01 +0100
4+
Subject: mtd: nand: Drop explicit test for built-in CONFIG_SPI_QPIC_SNAND
5+
6+
If CONFIG_SPI_QPIC_SNAND=m, but CONFIG_MTD_NAND_QCOM=n:
7+
8+
ERROR: modpost: "qcom_nandc_unalloc" [drivers/spi/spi-qpic-snand.ko] undefined!
9+
...
10+
11+
Fix this by dropping the explicit test for a built-in
12+
CONFIG_SPI_QPIC_SNAND completely. Kbuild handles multiple and mixed
13+
obj-y/obj-m rules for the same object file fine.
14+
15+
Reported-by: kernel test robot <lkp@intel.com>
16+
Closes: https://lore.kernel.org/oe-kbuild-all/202503280759.XhwLcV7m-lkp@intel.com/
17+
Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
18+
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
19+
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
20+
---
21+
drivers/mtd/nand/Makefile | 3 ---
22+
1 file changed, 3 deletions(-)
23+
24+
--- a/drivers/mtd/nand/Makefile
25+
+++ b/drivers/mtd/nand/Makefile
26+
@@ -3,11 +3,8 @@
27+
nandcore-objs := core.o bbt.o
28+
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
29+
obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
30+
-ifeq ($(CONFIG_SPI_QPIC_SNAND),y)
31+
obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o
32+
-else
33+
obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o
34+
-endif
35+
obj-y += onenand/
36+
obj-y += raw/
37+
obj-y += spi/

target/linux/generic/backport-6.12/421-v6.16-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch renamed to target/linux/generic/backport-6.12/412-v6.16-next-spi-spi-qpic-snand-validate-user-chip-specific-ECC-properties.patch

File renamed without changes.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
From 2abf107dcd797c60c86e9f17319cd1658862f6b2 Mon Sep 17 00:00:00 2001
2+
From: Gabor Juhos <j4g8y7@gmail.com>
3+
Date: Thu, 15 May 2025 20:58:05 +0200
4+
Subject: spi: spi-qpic-snand: use CW_PER_PAGE_MASK bitmask
5+
6+
Change the code to use the already defined CW_PER_PAGE_MASK
7+
bitmask along with the FIELD_PREP() macro instead of using
8+
magic values.
9+
10+
This makes the code more readable. It also syncs the affected
11+
codes with their counterparts in the 'qcom_nandc' driver, so it
12+
makes it easier to spot the differences between the two
13+
implementations.
14+
15+
No functional changes intended.
16+
17+
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
18+
Reviewed-by: Md Sadre Alam <quic_mdalam@quicinc.com>
19+
Link: https://patch.msgid.link/20250515-qpic-snand-use-bitmasks-v1-1-11729aeae73b@gmail.com
20+
Signed-off-by: Mark Brown <broonie@kernel.org>
21+
---
22+
drivers/spi/spi-qpic-snand.c | 31 ++++++++++++++++---------------
23+
1 file changed, 16 insertions(+), 15 deletions(-)
24+
25+
--- a/drivers/spi/spi-qpic-snand.c
26+
+++ b/drivers/spi/spi-qpic-snand.c
27+
@@ -483,7 +483,8 @@ static int qcom_spi_block_erase(struct q
28+
snandc->regs->cmd = snandc->qspi->cmd;
29+
snandc->regs->addr0 = snandc->qspi->addr1;
30+
snandc->regs->addr1 = snandc->qspi->addr2;
31+
- snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE));
32+
+ snandc->regs->cfg0 = cpu_to_le32((ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
33+
+ FIELD_PREP(CW_PER_PAGE_MASK, 0));
34+
snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
35+
snandc->regs->exec = cpu_to_le32(1);
36+
37+
@@ -544,8 +545,8 @@ static int qcom_spi_read_last_cw(struct
38+
snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
39+
snandc->regs->addr1 = snandc->qspi->addr2;
40+
41+
- cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
42+
- 0 << CW_PER_PAGE;
43+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
44+
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
45+
cfg1 = ecc_cfg->cfg1_raw;
46+
ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
47+
48+
@@ -687,8 +688,8 @@ static int qcom_spi_read_cw_raw(struct q
49+
qcom_clear_bam_transaction(snandc);
50+
raw_cw = num_cw - 1;
51+
52+
- cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
53+
- 0 << CW_PER_PAGE;
54+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
55+
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
56+
cfg1 = ecc_cfg->cfg1_raw;
57+
ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
58+
59+
@@ -808,8 +809,8 @@ static int qcom_spi_read_page_ecc(struct
60+
snandc->buf_start = 0;
61+
qcom_clear_read_regs(snandc);
62+
63+
- cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
64+
- (num_cw - 1) << CW_PER_PAGE;
65+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
66+
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
67+
cfg1 = ecc_cfg->cfg1;
68+
ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
69+
70+
@@ -904,8 +905,8 @@ static int qcom_spi_read_page_oob(struct
71+
qcom_clear_read_regs(snandc);
72+
qcom_clear_bam_transaction(snandc);
73+
74+
- cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
75+
- (num_cw - 1) << CW_PER_PAGE;
76+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
77+
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
78+
cfg1 = ecc_cfg->cfg1;
79+
ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
80+
81+
@@ -1015,8 +1016,8 @@ static int qcom_spi_program_raw(struct q
82+
int num_cw = snandc->qspi->num_cw;
83+
u32 cfg0, cfg1, ecc_bch_cfg;
84+
85+
- cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) |
86+
- (num_cw - 1) << CW_PER_PAGE;
87+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
88+
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
89+
cfg1 = ecc_cfg->cfg1_raw;
90+
ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
91+
92+
@@ -1098,8 +1099,8 @@ static int qcom_spi_program_ecc(struct q
93+
int num_cw = snandc->qspi->num_cw;
94+
u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
95+
96+
- cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
97+
- (num_cw - 1) << CW_PER_PAGE;
98+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
99+
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
100+
cfg1 = ecc_cfg->cfg1;
101+
ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
102+
ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
103+
@@ -1175,8 +1176,8 @@ static int qcom_spi_program_oob(struct q
104+
int num_cw = snandc->qspi->num_cw;
105+
u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
106+
107+
- cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) |
108+
- (num_cw - 1) << CW_PER_PAGE;
109+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
110+
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
111+
cfg1 = ecc_cfg->cfg1;
112+
ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
113+
ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
From d85d0380292a7e618915069c3579ae23c7c80339 Mon Sep 17 00:00:00 2001
2+
From: Gabor Juhos <j4g8y7@gmail.com>
3+
Date: Wed, 18 Jun 2025 22:22:49 +0200
4+
Subject: spi: spi-qpic-snand: reallocate BAM transactions
5+
6+
Using the mtd_nandbiterrs module for testing the driver occasionally
7+
results in weird things like below.
8+
9+
1. swiotlb mapping fails with the following message:
10+
11+
[ 85.926216] qcom_snand 79b0000.spi: swiotlb buffer is full (sz: 4294967294 bytes), total 512 (slots), used 0 (slots)
12+
[ 85.932937] qcom_snand 79b0000.spi: failure in mapping desc
13+
[ 87.999314] qcom_snand 79b0000.spi: failure to write raw page
14+
[ 87.999352] mtd_nandbiterrs: error: write_oob failed (-110)
15+
16+
Rebooting the board after this causes a panic due to a NULL pointer
17+
dereference.
18+
19+
2. If the swiotlb mapping does not fail, rebooting the board may result
20+
in a different panic due to a bad spinlock magic:
21+
22+
[ 256.104459] BUG: spinlock bad magic on CPU#3, procd/2241
23+
[ 256.104488] Unable to handle kernel paging request at virtual address ffffffff0000049b
24+
...
25+
26+
Investigating the issue revealed that these symptoms are results of
27+
memory corruption which is caused by out of bounds access within the
28+
driver.
29+
30+
The driver uses a dynamically allocated structure for BAM transactions,
31+
which structure must have enough space for all possible variations of
32+
different flash operations initiated by the driver. The required space
33+
heavily depends on the actual number of 'codewords' which is calculated
34+
from the pagesize of the actual NAND chip.
35+
36+
Although the qcom_nandc_alloc() function allocates memory for the BAM
37+
transactions during probe, but since the actual number of 'codewords'
38+
is not yet know the allocation is done for one 'codeword' only.
39+
40+
Because of this, whenever the driver does a flash operation, and the
41+
number of the required transactions exceeds the size of the allocated
42+
arrays the driver accesses memory out of the allocated range.
43+
44+
To avoid this, change the code to free the initially allocated BAM
45+
transactions memory, and allocate a new one once the actual number of
46+
'codewords' required for a given NAND chip is known.
47+
48+
Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
49+
Reviewed-by: Md Sadre Alam <quic_mdalam@quicinc.com>
50+
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
51+
Link: https://patch.msgid.link/20250618-qpic-snand-avoid-mem-corruption-v3-1-319c71296cda@gmail.com
52+
Signed-off-by: Mark Brown <broonie@kernel.org>
53+
---
54+
drivers/spi/spi-qpic-snand.c | 16 ++++++++++++++++
55+
1 file changed, 16 insertions(+)
56+
57+
--- a/drivers/spi/spi-qpic-snand.c
58+
+++ b/drivers/spi/spi-qpic-snand.c
59+
@@ -315,6 +315,22 @@ static int qcom_spi_ecc_init_ctx_pipelin
60+
61+
mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
62+
63+
+ /*
64+
+ * Free the temporary BAM transaction allocated initially by
65+
+ * qcom_nandc_alloc(), and allocate a new one based on the
66+
+ * updated max_cwperpage value.
67+
+ */
68+
+ qcom_free_bam_transaction(snandc);
69+
+
70+
+ snandc->max_cwperpage = cwperpage;
71+
+
72+
+ snandc->bam_txn = qcom_alloc_bam_transaction(snandc);
73+
+ if (!snandc->bam_txn) {
74+
+ dev_err(snandc->dev, "failed to allocate BAM transaction\n");
75+
+ ret = -ENOMEM;
76+
+ goto err_free_ecc_cfg;
77+
+ }
78+
+
79+
ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
80+
FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
81+
FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
From f820034864dd463cdcd2bebe7940f2eca0eb4223 Mon Sep 17 00:00:00 2001
2+
From: Gabor Juhos <j4g8y7@gmail.com>
3+
Date: Wed, 23 Jul 2025 10:06:43 +0200
4+
Subject: spi: spi-qpic-snand: don't hardcode ECC steps
5+
6+
NAND devices with different page sizes requires different number
7+
of ECC steps, yet the qcom_spi_ecc_init_ctx_pipelined() function
8+
sets 4 steps in 'ecc_cfg' unconditionally.
9+
10+
The correct number of the steps is calculated earlier in the
11+
function already, so use that instead of the hardcoded value.
12+
13+
Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
14+
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
15+
Link: https://patch.msgid.link/20250723-qpic-snand-fix-steps-v1-1-d800695dde4c@gmail.com
16+
Signed-off-by: Mark Brown <broonie@kernel.org>
17+
---
18+
drivers/spi/spi-qpic-snand.c | 2 +-
19+
1 file changed, 1 insertion(+), 1 deletion(-)
20+
21+
--- a/drivers/spi/spi-qpic-snand.c
22+
+++ b/drivers/spi/spi-qpic-snand.c
23+
@@ -308,7 +308,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
24+
ecc_cfg->bch_enabled = true;
25+
ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
26+
27+
- ecc_cfg->steps = 4;
28+
+ ecc_cfg->steps = cwperpage;
29+
ecc_cfg->cw_data = 516;
30+
ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
31+
bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;

target/linux/generic/backport-6.12/426-v6.17-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch renamed to target/linux/generic/backport-6.12/416-v6.17-mtd-nand-qpic-common-add-defines-for-ECC_MODE-values.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
5252
host->ecc_bytes_hw = 8;
5353
--- a/drivers/spi/spi-qpic-snand.c
5454
+++ b/drivers/spi/spi-qpic-snand.c
55-
@@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
55+
@@ -365,7 +365,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
5656
FIELD_PREP(ECC_SW_RESET, 0) |
5757
FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
5858
FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |

target/linux/generic/backport-6.12/427-v6.17-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch renamed to target/linux/generic/backport-6.12/417-v6.17-spi-spi-qpic-snand-add-support-for-8-bits-ECC-strength.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Signed-off-by: Mark Brown <broonie@kernel.org>
5555
ecc_cfg->bbm_size = 1;
5656
ecc_cfg->bch_enabled = true;
5757
ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
58-
@@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
58+
@@ -365,7 +376,7 @@ static int qcom_spi_ecc_init_ctx_pipelin
5959
FIELD_PREP(ECC_SW_RESET, 0) |
6060
FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
6161
FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
From 6bc829220b33da8522572cc50fdf5067c51d3bf3 Mon Sep 17 00:00:00 2001
2+
From: Gabor Juhos <j4g8y7@gmail.com>
3+
Date: Fri, 1 Aug 2025 09:58:35 +0200
4+
Subject: spi: spi-qpic-snand: use correct CW_PER_PAGE value for OOB write
5+
6+
The qcom_spi_program_oob() function uses only the last codeword to write
7+
the OOB data into the flash, but it sets the CW_PER_PAGE field in the
8+
CFG0 register as it would use all codewords.
9+
10+
It seems that this confuses the hardware somehow, and any access to the
11+
flash fails with a timeout error after the function is called. The problem
12+
can be easily reproduced with the following commands:
13+
14+
# dd if=/dev/zero bs=2176 count=1 > /tmp/test.bin
15+
1+0 records in
16+
1+0 records out
17+
# flash_erase /dev/mtd4 0 0
18+
Erasing 128 Kibyte @ 0 -- 100 % complete
19+
# nandwrite -O /dev/mtd4 /tmp/test.bin
20+
Writing data to block 0 at offset 0x0
21+
# nanddump -o /dev/mtd4 >/dev/null
22+
ECC failed: 0
23+
ECC corrected: 0
24+
Number of bad blocks: 0
25+
Number of bbt blocks: 0
26+
Block size 131072, page size 2048, OOB size 128
27+
Dumping data starting at 0x00000000 and ending at 0x00020000...
28+
[ 33.197605] qcom_snand 79b0000.spi: failure to read oob
29+
libmtd: error!: MEMREADOOB64 ioctl failed for mtd4, offset 0 (eraseblock 0)
30+
error 110 (Operation timed out)
31+
[ 35.277582] qcom_snand 79b0000.spi: failure in submitting cmd descriptor
32+
libmtd: error!: cannot read 2048 bytes from mtd4 (eraseblock 0, offset 2048)
33+
error 110 (Operation timed out)
34+
nanddump: error!: mtd_read
35+
36+
Change the code to use the correct CW_PER_PAGE value to avoid this.
37+
38+
Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface")
39+
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
40+
Link: https://patch.msgid.link/20250801-qpic-snand-oob-cwpp-fix-v1-1-f5a41b86af2e@gmail.com
41+
Signed-off-by: Mark Brown <broonie@kernel.org>
42+
---
43+
drivers/spi/spi-qpic-snand.c | 2 +-
44+
1 file changed, 1 insertion(+), 1 deletion(-)
45+
46+
--- a/drivers/spi/spi-qpic-snand.c
47+
+++ b/drivers/spi/spi-qpic-snand.c
48+
@@ -1204,7 +1204,7 @@ static int qcom_spi_program_oob(struct q
49+
u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
50+
51+
cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
52+
- FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
53+
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
54+
cfg1 = ecc_cfg->cfg1;
55+
ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
56+
ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;

0 commit comments

Comments
 (0)