From patchwork Mon Dec 10 15:24:24 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pantelis Antoniou X-Patchwork-Id: 204939 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 34AA92C0315 for ; Tue, 11 Dec 2012 02:24:42 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2BD924A04A; Mon, 10 Dec 2012 16:24:39 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id y39OITN+AaMz; Mon, 10 Dec 2012 16:24:38 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id ADC224A050; Mon, 10 Dec 2012 16:24:36 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DF3F34A050 for ; Mon, 10 Dec 2012 16:24:33 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id s5uSm52-RAFw for ; Mon, 10 Dec 2012 16:24:31 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from li42-95.members.linode.com (li42-95.members.linode.com [209.123.162.95]) by theia.denx.de (Postfix) with ESMTPS id 81A344A04A for ; Mon, 10 Dec 2012 16:24:29 +0100 (CET) Received: from sles11esa.localdomain (unknown [195.97.110.117]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: panto) by li42-95.members.linode.com (Postfix) with ESMTPSA id DEA319C10A; Mon, 10 Dec 2012 15:24:26 +0000 (UTC) From: Pantelis Antoniou To: Scott Wood Date: Mon, 10 Dec 2012 17:24:24 +0200 Message-Id: <1355153064-6008-1-git-send-email-panto@antoniou-consulting.com> X-Mailer: git-send-email 1.7.12 Cc: Tom Rini , Pantelis Antoniou , u-boot@lists.denx.de Subject: [U-Boot] [PATCH] [nand] Implement nand_extent_skip_bad X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de When accessing nand any bad blocks encountered are skipped, with no indication about the amount of bad blocks encountered. While this is normally fine, when you have to write a large amount of data in chunks, you need to account for the skipped amount due to the presence of the bad blocks. nand_extend_skip_bad() returns the offset where the next access should occur. Signed-off-by: Pantelis Antoniou --- drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ include/nand.h | 2 ++ 2 files changed, 52 insertions(+) diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2ba0c5e..a25a4cb 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -684,6 +684,56 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, return 0; } +/** + * nand_extent_skip_bad: + * + * Find the extent of a chunk, return the offset where it ends + * Blocks that are marked bad are skipped and the next block is examined + * instead as long as the extend is short enough to fit even after skipping the + * bad blocks. + * + * @param nand NAND device + * @param offset offset in flash + * @param length extend length + * @return next offset in case of success (loff_t)-1 on error + */ +loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length) +{ + size_t block_len, block_off; + loff_t block_start; + + if ((offset & (nand->writesize - 1)) != 0) { + printf ("%s: Attempt to check extend non page aligned data\n", + __func__); + return (loff_t)-1; + } + + while (length > 0) { + + if (offset >= nand->size) { + printf("%s: offset >= nand->size (%llx >= %llx)\n", + __func__, offset, nand->size); + return (loff_t)-1; + } + + block_start = offset & ~(loff_t)(nand->erasesize - 1); + block_off = offset & (nand->erasesize - 1); + block_len = nand->erasesize - block_off; + if (block_len > length) /* left over */ + block_len = length; + + if (!nand_block_isbad(nand, block_start)) + length -= block_len; + else + debug("%s: bad block at %llx (left %x)\n", + __func__, block_start, length); + + offset += block_len; + } + + return offset; +} + #ifdef CONFIG_CMD_NAND_TORTURE /** diff --git a/include/nand.h b/include/nand.h index dded4e2..710c11a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -168,3 +168,5 @@ __attribute__((noreturn)) void nand_boot(void); #define ENV_OFFSET_SIZE 8 int get_nand_env_oob(nand_info_t *nand, unsigned long *result); #endif + +loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length);