From patchwork Thu May 1 09:56:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 29474 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f71.google.com (mail-pa0-f71.google.com [209.85.220.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D5C62203F3 for ; Thu, 1 May 2014 09:58:13 +0000 (UTC) Received: by mail-pa0-f71.google.com with SMTP id kx10sf2840820pab.2 for ; Thu, 01 May 2014 02:58:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=ycf/fMbHAKeXh4+KOkRXeKmXLGdQrPnQIorfyVfL2rs=; b=KS4WCUNNPOpNuPD59gvqx7veoB4NmZe4tYooA0zqmAsyJ9+MQe9wWtLJVkEppK/bXm +lC3fSephQfjjS0imTSoG5+3gWg8ZcQHTw1fuWU7NySaIvmaz07rwLhJ0BcHzJVFms2V xza602PXwaIn9qNe9GLD+bnQrGM0ojw9GZW3HgBJBHVR0Uva0KuB3W4B8dC8VqaIdwpv wD0z9q76nrr1nCiuNknCJ+aVQmHnuXstk9m60mUwHbxga7LWRwaE4+LVJZbjhyupc18x VmJ9R9gLhijDK31gZN/CB6N1c8gyh/SbCbdv7h6rUClgHlmgoAyJFQvtGx4P0ECuOkx5 P38w== X-Gm-Message-State: ALoCoQmt4/m7n6Me1gadncVV0Pp882yxn2jY6GqEMr0gWf2IhmpupL0Jht6FfldaCIyZPevysP/G X-Received: by 10.66.124.168 with SMTP id mj8mr5068424pab.29.1398938292966; Thu, 01 May 2014 02:58:12 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.31.52 with SMTP id e49ls938285qge.19.gmail; Thu, 01 May 2014 02:58:12 -0700 (PDT) X-Received: by 10.221.74.200 with SMTP id yx8mr8062585vcb.3.1398938292835; Thu, 01 May 2014 02:58:12 -0700 (PDT) Received: from mail-vc0-f177.google.com (mail-vc0-f177.google.com [209.85.220.177]) by mx.google.com with ESMTPS id tn6si5962631vcb.75.2014.05.01.02.58.12 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 01 May 2014 02:58:12 -0700 (PDT) Received-SPF: none (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) client-ip=209.85.220.177; Received: by mail-vc0-f177.google.com with SMTP id if11so3655272vcb.36 for ; Thu, 01 May 2014 02:58:12 -0700 (PDT) X-Received: by 10.220.250.203 with SMTP id mp11mr8116631vcb.2.1398938292769; Thu, 01 May 2014 02:58:12 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp12954vcb; Thu, 1 May 2014 02:58:12 -0700 (PDT) X-Received: by 10.180.221.8 with SMTP id qa8mr1455102wic.39.1398938291833; Thu, 01 May 2014 02:58:11 -0700 (PDT) Received: from mail-wi0-f173.google.com (mail-wi0-f173.google.com [209.85.212.173]) by mx.google.com with ESMTPS id t4si582545wiy.14.2014.05.01.02.58.11 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 01 May 2014 02:58:11 -0700 (PDT) Received-SPF: none (google.com: lee.jones@linaro.org does not designate permitted sender hosts) client-ip=209.85.212.173; Received: by mail-wi0-f173.google.com with SMTP id bs8so389483wib.12 for ; Thu, 01 May 2014 02:58:11 -0700 (PDT) X-Received: by 10.180.21.180 with SMTP id w20mr1543017wie.34.1398938291314; Thu, 01 May 2014 02:58:11 -0700 (PDT) Received: from lee--X1.home (host109-148-238-223.range109-148.btcentralplus.com. [109.148.238.223]) by mx.google.com with ESMTPSA id bj5sm2696494wib.3.2014.05.01.02.58.09 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 01 May 2014 02:58:10 -0700 (PDT) From: Lee Jones To: linux-kernel@vger.kernel.org Cc: computersforpeace@gmail.com, linux-mtd@lists.infradead.org, kernel@stlinux.com, Lee Jones Subject: [PATCH 31/47] mtd: nand: stm_nand_bch: update flash-resident BBT(s) Date: Thu, 1 May 2014 10:56:38 +0100 Message-Id: <1398938214-17847-32-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1398938214-17847-1-git-send-email-lee.jones@linaro.org> References: <1398938214-17847-1-git-send-email-lee.jones@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lee.jones@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Search for suitable block, erase and write table data to flash. If any errors occur on selected block, mark it as bad and select another one. Keep trying until both the Primary and Mirror BBTs are a) synced and b) written successfully to flash. Signed-off-by: Lee Jones --- drivers/mtd/nand/stm_nand_bch.c | 143 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/drivers/mtd/nand/stm_nand_bch.c b/drivers/mtd/nand/stm_nand_bch.c index 8b70a36..e909d80 100644 --- a/drivers/mtd/nand/stm_nand_bch.c +++ b/drivers/mtd/nand/stm_nand_bch.c @@ -59,6 +59,11 @@ static uint8_t ibbt_sigs[2][NAND_IBBT_SIGLEN] = { {'1', 't', 'b', 'B'}, }; +static char *bbt_strs[] = { + "primary", + "mirror", +}; + /* IBBT header */ struct nand_ibbt_header { uint8_t signature[4]; /* "Bbt0" or "1tbB" signature */ @@ -787,6 +792,144 @@ static int bch_write_bbt_data(struct nandi_controller *nandi, return 0; } +/* + * Update Flash-resident BBT: + * erase/search suitable block, and write table data to Flash + */ +static int bch_update_bbt(struct nandi_controller *nandi, + struct nandi_bbt_info *bbt_info, + int bak, uint8_t vers) +{ + loff_t offs; + uint32_t block; + uint32_t block_lower; + uint32_t block_other; + + block_other = bbt_info->bbt_block[(bak+1)%2]; + block_lower = nandi->blocks_per_device - NAND_IBBT_NBLOCKS; + + for (block = bbt_info->bbt_block[bak]; block >= block_lower; block--) { + offs = (loff_t)block << nandi->block_shift; + + /* Skip if block used by other table */ + if (block == block_other) + continue; + + /* Skip if block is marked bad */ + if (bbt_is_block_bad(bbt_info->bbt, block)) + continue; + + /* Erase block, mark bad and skip on failure */ + if (bch_erase_block(nandi, offs) & NAND_STATUS_FAIL) { + dev_info(nandi->dev, + "failed to erase block [%u:0x%012llx] while updating BBT\n", + block, offs); + vers++; + bbt_set_block_mark(bbt_info->bbt, block, + BBT_MARK_BAD_WEAR); + continue; + } + + /* Write BBT, mark bad and skip on failure */ + if (bch_write_bbt_data(nandi, bbt_info, block, bak, vers)) { + dev_info(nandi->dev, + "failed to write BBT to block [%u:0x%012llx]\n", + block, offs); + vers++; + bbt_set_block_mark(bbt_info->bbt, block, + BBT_MARK_BAD_WEAR); + continue; + } + + /* Success */ + bbt_info->bbt_block[bak] = block; + bbt_info->bbt_vers[bak] = vers; + break; + } + + /* No space in BBT area */ + if (block < block_lower) { + dev_err(nandi->dev, "no space left in BBT area\n"); + dev_err(nandi->dev, "failed to update %s BBT\n", bbt_strs[bak]); + return -ENOSPC; + } + + dev_info(nandi->dev, "wrote BBT [%s:%u] at 0x%012llx [%u]\n", + bbt_strs[bak], vers, offs, block); + + return 0; +} + +#define NAND_IBBT_UPDATE_PRIMARY 0x1 +#define NAND_IBBT_UPDATE_MIRROR 0x2 +#define NAND_IBBT_UPDATE_BOTH (NAND_IBBT_UPDATE_PRIMARY | \ + NAND_IBBT_UPDATE_MIRROR) +static char *bbt_update_strs[] = { + "", + "primary", + "mirror", + "both", +}; + +/* + * Update Flash-resident BBT(s): + * incrementing 'vers' number if required, and ensuring Primary + * and Mirror are kept in sync + */ +static int bch_update_bbts(struct nandi_controller *nandi, + struct nandi_bbt_info *bbt_info, + unsigned int update, uint8_t vers) +{ + int err; + + dev_info(nandi->dev, "updating %s BBT(s)\n", bbt_update_strs[update]); + + do { + /* Update Primary if specified */ + if (update & NAND_IBBT_UPDATE_PRIMARY) { + err = bch_update_bbt(nandi, bbt_info, NAND_IBBT_PRIMARY, + vers); + /* Bail out on error (e.g. no space left in BBT area) */ + if (err) + return err; + + /* + * If update resulted in a new BBT version + * (e.g. Erase/Write fail on BBT block) update version + * here, and force update of other table. + */ + if (bbt_info->bbt_vers[NAND_IBBT_PRIMARY] != vers) { + vers = bbt_info->bbt_vers[NAND_IBBT_PRIMARY]; + update = NAND_IBBT_UPDATE_MIRROR; + } + } + + /* Update Mirror if specified */ + if (update & NAND_IBBT_UPDATE_MIRROR) { + err = bch_update_bbt(nandi, bbt_info, NAND_IBBT_MIRROR, + vers); + /* Bail out on error (e.g. no space left in BBT area) */ + if (err) + return err; + + /* + * If update resulted in a new BBT version + * (e.g. Erase/Write fail on BBT block) update version + * here, and force update of other table. + */ + if (bbt_info->bbt_vers[NAND_IBBT_MIRROR] != vers) { + vers = bbt_info->bbt_vers[NAND_IBBT_MIRROR]; + update = NAND_IBBT_UPDATE_PRIMARY; + } + } + + /* Continue, until Primary and Mirror versions are in sync */ + } while (bbt_info->bbt_vers[NAND_IBBT_PRIMARY] != + bbt_info->bbt_vers[NAND_IBBT_MIRROR]); + + return 0; +} + /* Scan block for IBBT signature */ static int bch_find_ibbt_sig(struct nandi_controller *nandi, uint32_t block, int *bak, uint8_t *vers,