From patchwork Sun Sep 13 04:04:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 3297 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id DB8761C2CE3 for ; Sun, 13 Sep 2026 06:08:29 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=gmail.com; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-25846-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-25846-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 5AA833B24C for ; Sun, 13 Sep 2026 04:05:23 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 249AE38A725; Sun, 13 Sep 2026 04:05:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BoIazdCv" X-Original-To: linux-sunxi@lists.linux.dev Received: from mail-oa2-f12.google.com (mail-oa2-f12.google.com [74.125.231.76]) (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 7E84338DC61 for ; Sun, 13 Sep 2026 04:05:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.231.76 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789272323; cv=none; b=CzAEoyqXgqVw8cyCuY8OYU0CGG/3DXvNwG9LkvwydbrgFjJ0KMw3tFLf6bkTQLH4Psr6MqjO4i7pY/2IH6g8OZMtRZ8HyEXWcPxVgYT5W8KUxqmtFnFVMpDxsJlQ9xvynOHNqmtc+D8upZvaQzzyneDsDgHgthWx6cUYINyzLLY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789272323; c=relaxed/simple; bh=BwaJyFzlFHttOpzQWC5cJaXOsCB26F1Sbm59Qoabces=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XVHa1+VSdRrDq37uIY/tp1SZ4wlIbDBwvDwgeDKP3YL8F2mlWRcAIFJ6FAXAjswwqa3e4tdvdVUF2amezP8CpPUcvDk0/JZTLb3voQevkIgMSGJ36vyL1/Twk1sYB/OfmUThSnIoSXaoKN8Cl3mib11WBP+hn7BeuEZM3a6CvIc= 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=BoIazdCv; arc=none smtp.client-ip=74.125.231.76 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-oa2-f12.google.com with SMTP id 586e51a60fabf-466cc9ab667so1501842fac.0 for ; Sat, 12 Sep 2026 21:05:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1789272316; x=1789877116; 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=iXMUiYhcNcQU3o5YIAteHcfA6in7/WsaQMspzMho3uo=; b=BoIazdCvDxpLN456idfDmxeEfDl52Ea+8ADqa6x5YYvdlISkImZrnhnwmIfASP4F/i XaWndMkNeN5GI51u2scyFVm700aVQVMAcux4XBT5dbjDGuRFf60ME9AzspDJw51kfeDT ku0/pG1IYj1PPRXlzF3CJESJRGiTsEGn0mCB/WxFJ03BOLwTyO1+DNzANbMimX7S8L7c WdoQvLloZn40epuecMevaA6Icx9nboIuRPuItQfqD9Jr477+5T8NyivcK4f+7FSk4tvU zMi7aNhKtNrLfNIBmVY4i1aV5gUTYVwWx3pWys2FuSNEsVb3e1JUGa/ttjIsfmjXfY2m 7CPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789272316; x=1789877116; 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=iXMUiYhcNcQU3o5YIAteHcfA6in7/WsaQMspzMho3uo=; b=V/hICHjb/BIA0/sMBEKJe4GuOrqMoyEOPoXqdO3ATUhF+5mUknVFQ9ebQNWteQbJAZ knUc/vHwWp5vhCkTtrrkfJIpAK5/Nqzf5RvbaTjyrDv+eQSo/56dgJGqlKXx0EdKs30z eJB2aBF6iBzRukvXlQI9rKA4wSZdQdVkAeLqAMulG6mgOYnPjDXWuopHPpBZc3JpA630 bXgCOfBm+sEhKwz772JgHJVYYgRh7/K3xsfABjQ9jmc5ZWIqyb/FgN7e5/CUcVTkB0jx d9GkEx2fwOpgrUHEx23hfngBci9ZWXepnjl1Ip5tjmbit/PIBb3QdrZX+aLZAOVJoqvk nvhw== X-Forwarded-Encrypted: i=1; AKwUvBwn7EF3ltkIiBRIWOoUXQl4FQD/O/pJ2CnXGYIbDkVGjVpCRMEwwChbnn177Myzvw4yJpxyr/dN/suMmw==@lists.linux.dev X-Gm-Message-State: AFuF++m2Pb2dVdBsh2si7MauqomACle8lDdVQk3AVv/awLxQ0ukqOcUJ KFAktFDH8xEf3+2/GcCJ59Wx5bmUIeqaIQ5mVGerbyFvfY5AbrWcemGi X-Gm-Gg: AYBFou0OeJVmDHkiWrrgLOefFRlk8ZrgtZy5+hOkBl43Ixd2VIGvjSYXoYXSaFH1PV6 3MF1Vm2vGhqeIlpHtaN2Gp6riGD112O2pE2s0vpYdURjLzGhoUVAPM3/RxYXsvjQYdj2VnLGV15 buCVn+GxTu3+G5bVj0TKKZipYXozXRGBpPtNI1EKs3Uc8CtbONEkwg9Pi93AmHOW0j9mkaiJpNQ LbsWQiHITKk6yrktBqpA5b4WkXnCOxiSkc/yEKe+9neI/pAuqlsfcSSVYXYu8H4JSbRRs1GzPXZ RRcZs5Z+yBC1EhLUL+l+CpFlRovSWsmcY5jof9ihalj6BioXRTxQTDNB40BGka8sqLzQJbB5RJx iRifQsSzgT4YmB+rY1xUOp1G4p0Mqcbk5bT0hPn32JLp/ttRAa/sXZdB5Ys3EK0cYsE7ygCsH+f bkh+I326FykDDkhgyoxCYUhTfGaOCLuqY//cpNnH64myzqg9Y8e23xQXzllslZ5AXmPe6SRvT+z wkVi7cSSklYmWiw1Z1A4HH2LSUlBoiBeFVz0nx7W/+M0i6OPOwabfqrL+klNg/sYXkBT3sPJyhI 5ZoTZptN7ivWAgDwy+pMo0/DcE4ca2uAZhhU5+BjCFkOW51cTBXIZ8PQ81hmDjltrC6dz3nD6Xk /wkxt4IyepYCs3c48UcYvITefcq1yFg== X-Received: by 2002:a05:6870:b40e:b0:43a:c6c1:e40d with SMTP id 586e51a60fabf-47de8fa793emr7029141fac.16.1789272316328; Sat, 12 Sep 2026 21:05:16 -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 586e51a60fabf-47df8699647sm6011535fac.5.2026.09.12.21.05.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 12 Sep 2026 21:05:15 -0700 (PDT) From: James Hilliard Date: Sat, 12 Sep 2026 22:04:57 -0600 Subject: [PATCH v4 06/17] 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: <20260912-submit-sunxi-nand-vendor-oob-layout-v1-v4-6-4a64bed94229@gmail.com> References: <20260912-submit-sunxi-nand-vendor-oob-layout-v1-v4-0-4a64bed94229@gmail.com> In-Reply-To: <20260912-submit-sunxi-nand-vendor-oob-layout-v1-v4-0-4a64bed94229@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 X-Mailer: b4 0.15.2 X-Rspamd-Server: rspamd-worker-8404 X-Spamd-Result: default: False [4.34 / 15.00]; RBL_SENDERSCORE(2.00)[172.234.253.10:from]; SUSPICIOUS_RECIPS(1.50)[]; DMARC_POLICY_SOFTFAIL(1.00)[gmail.com : SPF not aligned (relaxed), No valid DKIM,none]; MAILLIST(-0.15)[generic]; BAD_REP_POLICIES(0.10)[]; MIME_GOOD(-0.10)[text/plain]; HAS_LIST_UNSUB(-0.01)[]; ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1]; FROM_HAS_DN(0.00)[]; PRECEDENCE_BULK(0.00)[]; TAGGED_RCPT(0.00)[dt]; FREEMAIL_CC(0.00)[lists.infradead.org,vger.kernel.org,lists.linux.dev,gmail.com]; RCPT_COUNT_TWELVE(0.00)[20]; FORGED_SENDER_MAILLIST(0.00)[]; RCVD_COUNT_FIVE(0.00)[6]; ASN(0.00)[asn:63949, ipnet:172.234.224.0/19, country:SG]; FREEMAIL_FROM(0.00)[gmail.com]; FREEMAIL_TO(0.00)[bootlin.com,nod.at,ti.com,kernel.org,gmail.com,sholland.org,socionext.com]; R_SPF_ALLOW(0.00)[+ip4:172.234.253.10:c]; TO_DN_SOME(0.00)[]; FROM_NEQ_ENVFROM(0.00)[jameshilliard1@gmail.com,linux-sunxi@lists.linux.dev]; FORGED_RECIPIENTS_MAILLIST(0.00)[]; RCVD_TLS_LAST(0.00)[]; MIME_TRACE(0.00)[0:+]; TAGGED_FROM(0.00)[bounces-25846-noreply=patchwork.local]; MID_RHS_MATCH_FROM(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[] X-Rspamd-Queue-Id: DB8761C2CE3 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") 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);