From patchwork Mon Sep 14 03:01:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 3320 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114]) by mxe881.netcup.net (Postfix) with ESMTPS id 0B20D1C3F00 for ; Mon, 14 Sep 2026 05:03:46 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=gmail.com; spf=pass (sender IP is 172.105.105.114) smtp.mailfrom=linux-sunxi+bounces-25880-noreply=patchwork.local@lists.linux.dev smtp.helo=tor.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.105.105.114 as permitted sender) client-ip=172.105.105.114; envelope-from=linux-sunxi+bounces-25880-noreply=patchwork.local@lists.linux.dev; helo=tor.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by tor.lore.kernel.org (Postfix) with ESMTP id AC7C72F3DA for ; Mon, 14 Sep 2026 03:02:09 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DDF40349CD6; Mon, 14 Sep 2026 03:01:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hooqoGlj" X-Original-To: linux-sunxi@lists.linux.dev Received: from mail-ot1-f51.google.com (mail-ot1-f51.google.com [209.85.210.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF9D2334C39 for ; Mon, 14 Sep 2026 03:01:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789354910; cv=none; b=eiV2VjLTRg44+Zfb90GgG4+FWbbM1+W46g2kvkhr0BUoUfuz00DwUpmPjx9RZjaDuNbmZKuN5bJgZopXMjaTUNkg9tlI7hydBoNCaEZgCc/Y//7DUy1jFVaILCrnsAxmgLle2afeDcWzE1dFF+c6NvJ3cW9+8ujlNMrW+w5VZOg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789354910; c=relaxed/simple; bh=QuwwqJoNNeFbRXCees1KSU/os0gxTVKzY6QPcLIi7JU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EizU83Z5hi0wmsPNmX36h6LkiBC5AMXrMAW0lylzjQZym/UFugsHziRvSE8HDqQIzdKQ30nxa6rfp9qv0MyCjkInjNTrts9jXFxbbd0A2+yEywv7KsoPmiI1/WL31B/YQfxYv7qw8vnEnuJOEZaba/qjZ4CvAshPVDINGqPITps= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hooqoGlj; arc=none smtp.client-ip=209.85.210.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ot1-f51.google.com with SMTP id 46e09a7af769-7f4e729368fso2938123a34.0 for ; Sun, 13 Sep 2026 20:01:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1789354906; x=1789959706; darn=lists.linux.dev; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=j2vD4BC1COzN8qzLeVpRCLcx09AvVc6YiLKflTDkdf0=; b=hooqoGlj0/NNdb3pNRkNypjDZ6ey3U6u1wIoX582fgeDJlS3oNlX6mL/ZudFHXhmsj Qh/aen5PzBzRmkzKBcevl8zjtlaRf8noJtJZryTlVISQ1igFWN6/zt5YzLnLjcHlf+mW XcTshAEjB4pbzoU+qbb4UAAxeZBt5hKbgm0H8Qg13kWl3IpBOMJe207n6Swi/mpLcuyl cV/DA16qvWDVNx4igUpC1vOxJGR/wnKA8pQp3r+sK12+0kNDLh7R1dm80PhXhzHneU94 j2Nvy70WsuyDCr1EuguQcnOfNV+sdxplq/3wWBG+jn+NwYTLDQAUa6cmSuzx0cE/FE2S cz8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789354906; x=1789959706; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=j2vD4BC1COzN8qzLeVpRCLcx09AvVc6YiLKflTDkdf0=; b=m9dEh/SHi4Bk8SMx7bXK3dL+yIIf9PZEJNmwyJqFKEH2lrsP5taZV6Nn6XlWlPwsmn jv6h5qwSzPqz7O+c1y6HHy3HuPsKWTrjTygZ6pA1+dtTtEnbBBE2p0KGK5IGR3d5d4hf d49kOXjiMY1z9lP6+eq1eM+X4lY3hvqfhb2tRRzaftcgYYnEHaq5aPvQjsaOcQfDHJy+ hs5qBDvSYPCU1AGgwHb9+dSn3Hri5Jx5aWbT2+w18bbYYxl6/F9RWQPr+JVPteJCMY7f AHmH0vIRXt1kp1i3aGwWvuM9A1baYq7vTwhHPCCfRI8U1t46NcInDkPqtO9DaCbOUZEE tb7g== X-Forwarded-Encrypted: i=1; AKwUvBzqflDPIxWQXAhikRyu+yuF1zd/w6f0vwzT4Y2r4CANuNt/CHS1riF9BwJA4a8bOYbXFBsuumiYOKXphA==@lists.linux.dev X-Gm-Message-State: AFuF++keKGYIomDJxUisyNsF4BepeASBo76VqG+j06/2BlkMNuI8tR03 2dC+gJULw/mRxt3eX+HIs9Is9x+IxFhBfnU8+BjJQktbl8Uyn2YKhvFf2XUCMw== X-Gm-Gg: AYBFou3MV2qVeK+57FG6W25L+UQcmq7qXGKtdzu4FXch82hqWpMVecWYM67OwiO5pvz tv8WlhMupn+MRnrcCaOJUW5OomPTY5rYitSJF1A5CwYNIXdazB40NAfOnCFa6rNpwmLtC9qjR7t oXLyXBT0pUR2KMbNrA/q9QGYLoEFAWah9ZC52ajR+TbquTq2JGiMEOV91fQ4c2HEA3JXiNNLNSf ksecD4jDLzLE3O7NW1hdU4qLL+nJLQkx4BpJXp0iWyqTLkeyFDkzf1uqxtTfKK2l0MKMJ3FRD7P yuPL3JnMPtcx4l9K8iboEYhHXlM/YNYDwNXyxntOFGpy1a/jDIfiZXRcNbF771Gaj0ehJOvXvn+ znflnB1U3FBpgfvogTzowWYjRd8cD7UyMIyu72Xn3eT/N1aA7ky/6pFfWxmPD54mLUYBHMTTzYO 754yhVfhZRHJ43eJR/uECcZgau2maVEmNWwyDuKz/F69ax/sek/XTWFs4UWMxz+qs8JHzqRoxs4 xxn+xiB5Cwzk70MzrdreOR6J9daPZk5K3OPsUq/sTtZNcwskfJ2sujPYiYfs4ryRB/miFhC9pWi g4s0IfXpOEsQqWI88Dgen22ehMRO0ooBf3oagsEW4LNHp2IVoJUlxIXW0dD17QS8hUZHp1pNCRD owdDjWlena65g6Wy75JaRM8SebjZ19A== X-Received: by 2002:a05:6830:3886:b0:7fa:ac4f:790 with SMTP id 46e09a7af769-8089a150dcamr251581a34.28.1789354906207; Sun, 13 Sep 2026 20:01:46 -0700 (PDT) Received: from [127.0.1.1] (184-96-157-145.hlrn.qwest.net. [184.96.157.145]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-803f60feba1sm10619014a34.13.2026.09.13.20.01.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Sep 2026 20:01:45 -0700 (PDT) From: James Hilliard Date: Sun, 13 Sep 2026 21:01:12 -0600 Subject: [PATCH v5 06/18] mtd: rawnand: sunxi: propagate buffer and column transfer errors Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20260913-submit-sunxi-nand-vendor-oob-layout-v1-v5-6-7d711076a6f7@gmail.com> References: <20260913-submit-sunxi-nand-vendor-oob-layout-v1-v5-0-7d711076a6f7@gmail.com> In-Reply-To: <20260913-submit-sunxi-nand-vendor-oob-layout-v1-v5-0-7d711076a6f7@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Maxime Ripard , Richard Genoud , Masahiro Yamada , Boris Brezillon , Brian Norris Cc: linux-mtd@lists.infradead.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, James Hilliard , stable@vger.kernel.org X-Mailer: b4 0.15.2 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= The PIO buffer helpers stop on a FIFO or completion timeout but return no status. Their hardware-ECC callers also ignore column-change failures, including the extra-OOB paths used after DMA. A read can therefore report success with incomplete data, and a write can issue PAGEPROG after a failed transfer. Return transfer errors through the randomizer and OOB helpers to the page callbacks. Always disable the randomizer after a buffer transfer, and let the existing page error exits disable ECC and skip program-end. Only advance the extra-OOB cursor after a successful transfer. Keep the corrected-bit count separate from transport status so successful OOB reads do not overwrite it. If any legacy DMA OOB read fails, discard the ECC statistics from that attempt before the caller retries in PIO. Leave the successful transfer sequence and OOB representation unchanged. Fixes: 1fef62c1423b ("mtd: nand: add sunxi NAND flash controller support") Cc: stable@vger.kernel.org Signed-off-by: James Hilliard --- drivers/mtd/nand/raw/sunxi_nand.c | 220 ++++++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 79 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 3f506d0666a1..72b79f893e29 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -644,7 +644,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs) writel(ctl, nfc->regs + NFC_REG_CTL); } -static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) +static int sunxi_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) { struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); @@ -660,7 +660,7 @@ static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); if (ret) - break; + return ret; writel(cnt, nfc->regs + NFC_REG_CNT); tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; @@ -672,17 +672,19 @@ static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0); if (ret) - break; + return ret; if (buf) memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, cnt); offs += cnt; } + + return 0; } -static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, - int len) +static int sunxi_nfc_write_buf(struct nand_chip *nand, const u8 *buf, + int len) { struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); @@ -698,7 +700,7 @@ static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); if (ret) - break; + return ret; writel(cnt, nfc->regs + NFC_REG_CNT); memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); @@ -712,10 +714,12 @@ static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0); if (ret) - break; + return ret; offs += cnt; } + + return 0; } /* These seed values have been extracted from Allwinner's BSP */ @@ -865,23 +869,31 @@ static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm) bbm[1] ^= sunxi_nfc_randomizer_step(state, 8); } -static void sunxi_nfc_randomizer_write_buf(struct nand_chip *nand, - const uint8_t *buf, int len, - bool ecc, int page) +static int sunxi_nfc_randomizer_write_buf(struct nand_chip *nand, + const u8 *buf, int len, + bool ecc, int page) { + int ret; + sunxi_nfc_randomizer_config(nand, page, ecc); sunxi_nfc_randomizer_enable(nand); - sunxi_nfc_write_buf(nand, buf, len); + ret = sunxi_nfc_write_buf(nand, buf, len); sunxi_nfc_randomizer_disable(nand); + + return ret; } -static void sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, uint8_t *buf, - int len, bool ecc, int page) +static int sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, u8 *buf, + int len, bool ecc, int page) { + int ret; + sunxi_nfc_randomizer_config(nand, page, ecc); sunxi_nfc_randomizer_enable(nand); - sunxi_nfc_read_buf(nand, buf, len); + ret = sunxi_nfc_read_buf(nand, buf, len); sunxi_nfc_randomizer_disable(nand); + + return ret; } static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand) @@ -1152,17 +1164,25 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, u32 pattern_found; bool bbm = !step; bool erased; - int ret; + int ret, bitflips; /* From the controller point of view, we are at step 0 */ const int nfc_step = 0; - if (*cur_off != data_off) - nand_change_read_column_op(nand, data_off, NULL, 0, false); + if (*cur_off != data_off) { + ret = nand_change_read_column_op(nand, data_off, NULL, 0, false); + if (ret) + return ret; + } - sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page); + ret = sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page); + if (ret) + return ret; - if (data_off + ecc->size != oob_off) - nand_change_read_column_op(nand, oob_off, NULL, 0, false); + if (data_off + ecc->size != oob_off) { + ret = nand_change_read_column_op(nand, oob_off, NULL, 0, false); + if (ret) + return ret; + } ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); if (ret) @@ -1184,13 +1204,13 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, pattern_found = readl(nfc->regs + nfc->caps->reg_pat_found); pattern_found = field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found); - ret = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, - nfc_step, readl(nfc->regs + NFC_REG_ECC_ST), - pattern_found, user_data_sz, &erased); + bitflips = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL, + nfc_step, readl(nfc->regs + NFC_REG_ECC_ST), + pattern_found, user_data_sz, &erased); if (erased) return 1; - if (ret < 0) { + if (bitflips < 0) { if (!(nand->options & NAND_NEED_SCRAMBLING)) memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); @@ -1202,17 +1222,22 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand, memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); if (oob_required) { - nand_change_read_column_op(nand, oob_off, NULL, 0, - false); - sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + user_data_sz, - true, page); + ret = nand_change_read_column_op(nand, oob_off, NULL, 0, + false); + if (ret) + return ret; + ret = sunxi_nfc_randomizer_read_buf(nand, oob, + ecc->bytes + user_data_sz, + true, page); + if (ret) + return ret; sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, nfc_step, bbm, page, user_data_sz); } } - sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, ret); + sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, bitflips); return 0; } @@ -1245,31 +1270,39 @@ static int sunxi_get_ecc_offset(struct sunxi_nand_chip *sunxi_nand, sunxi_nfc_user_data_sz(sunxi_nand, step); } -static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, - u8 *oob, int *cur_off, - bool randomize, int page) +static int sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + u8 *oob, int *cur_off, + bool randomize, int page) { struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct mtd_info *mtd = nand_to_mtd(nand); struct nand_ecc_ctrl *ecc = &nand->ecc; int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps); int len = mtd->oobsize - offset; + int ret; if (len <= 0) - return; + return 0; - if (!cur_off || *cur_off != (offset + mtd->writesize)) - nand_change_read_column_op(nand, mtd->writesize + offset, - NULL, 0, false); + if (!cur_off || *cur_off != (offset + mtd->writesize)) { + ret = nand_change_read_column_op(nand, mtd->writesize + offset, + NULL, 0, false); + if (ret) + return ret; + } if (!randomize) - sunxi_nfc_read_buf(nand, oob + offset, len); + ret = sunxi_nfc_read_buf(nand, oob + offset, len); else - sunxi_nfc_randomizer_read_buf(nand, oob + offset, len, - false, page); + ret = sunxi_nfc_randomizer_read_buf(nand, oob + offset, len, + false, page); + if (ret) + return ret; if (cur_off) *cur_off = mtd->oobsize + mtd->writesize; + + return 0; } static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf, @@ -1340,21 +1373,24 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf u8 *data = buf + data_off; u8 *oob = nand->oob_poi + oob_off; bool erased; + int bitflips; - ret = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL, - oob_required ? oob : NULL, - i, status, pattern_found, - user_data_sz, &erased); + bitflips = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL, + oob_required ? oob : NULL, + i, status, pattern_found, + user_data_sz, &erased); /* ECC errors are handled in the second loop. */ - if (ret < 0) + if (bitflips < 0) continue; if (oob_required && !erased) { /* TODO: use DMA to retrieve OOB */ - nand_change_read_column_op(nand, - mtd->writesize + oob_off, - oob, ecc->bytes + user_data_sz, false); + ret = nand_change_read_column_op(nand, mtd->writesize + oob_off, + oob, ecc->bytes + user_data_sz, + false); + if (ret) + goto err_stats; sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, !i, page, user_data_sz); @@ -1363,7 +1399,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf if (erased) raw_mode = 1; - sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret); + sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, bitflips); } if (status & NFC_ECC_ERR_MSK(nfc)) { @@ -1381,23 +1417,27 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf mtd->writesize + oob_off, user_data_sz, &max_bitflips); - if (ret < 0) { - /* The caller retries the whole read in PIO mode. */ - mtd->ecc_stats.corrected = corrected; - mtd->ecc_stats.failed = failed; - return ret; - } + if (ret < 0) + goto err_stats; if (ret) raw_mode = 1; } } - if (oob_required) - sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, - NULL, !raw_mode, - page); + if (oob_required) { + ret = sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, + NULL, !raw_mode, page); + if (ret) + goto err_stats; + } return max_bitflips; + +err_stats: + /* The caller retries the whole read in PIO mode. */ + mtd->ecc_stats.corrected = corrected; + mtd->ecc_stats.failed = failed; + return ret; } static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, @@ -1415,13 +1455,21 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, /* From the controller point of view, we are at step 0 */ const int nfc_step = 0; - if (data_off != *cur_off) - nand_change_write_column_op(nand, data_off, NULL, 0, false); + if (data_off != *cur_off) { + ret = nand_change_write_column_op(nand, data_off, NULL, 0, false); + if (ret) + return ret; + } - sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page); + ret = sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page); + if (ret) + return ret; - if (data_off + ecc->size != oob_off) - nand_change_write_column_op(nand, oob_off, NULL, 0, false); + if (data_off + ecc->size != oob_off) { + ret = nand_change_write_column_op(nand, oob_off, NULL, 0, false); + if (ret) + return ret; + } ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); if (ret) @@ -1447,27 +1495,35 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand, return 0; } -static void sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand, - u8 *oob, int *cur_off, - int page) +static int sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand, + u8 *oob, int *cur_off, + int page) { struct mtd_info *mtd = nand_to_mtd(nand); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct nand_ecc_ctrl *ecc = &nand->ecc; int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps); int len = mtd->oobsize - offset; + int ret; if (len <= 0) - return; + return 0; - if (!cur_off || *cur_off != offset) - nand_change_write_column_op(nand, offset + mtd->writesize, - NULL, 0, false); + if (!cur_off || *cur_off != offset) { + ret = nand_change_write_column_op(nand, offset + mtd->writesize, + NULL, 0, false); + if (ret) + return ret; + } - sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page); + ret = sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page); + if (ret) + return ret; if (cur_off) *cur_off = mtd->oobsize + mtd->writesize; + + return 0; } static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf, @@ -1506,9 +1562,12 @@ static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf, raw_mode = true; } - if (oob_required) - sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off, - !raw_mode, page); + if (oob_required) { + ret = sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off, + !raw_mode, page); + if (ret) + goto out; + } ret = max_bitflips; out: @@ -1635,8 +1694,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand, } if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) - sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, - &cur_off, page); + ret = sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, + &cur_off, page); out: sunxi_nfc_hw_ecc_disable(nand); @@ -1759,10 +1818,13 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand, if (ret) return ret; - if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) + if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) { /* TODO: use DMA to transfer extra OOB bytes ? */ - sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, - NULL, page); + ret = sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi, + NULL, page); + if (ret) + return ret; + } return nand_prog_page_end_op(nand);