Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756573AbbDPCT4 (ORCPT ); Wed, 15 Apr 2015 22:19:56 -0400 Received: from mailout.micron.com ([137.201.242.129]:57694 "EHLO mailout.micron.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752508AbbDPCTt (ORCPT ); Wed, 15 Apr 2015 22:19:49 -0400 From: =?gb2312?B?UGV0ZXIgUGFuIMXLtrAgKHBldGVycGFuZG9uZyk=?= To: "dwmw2@infradead.org" , Brian Norris , "fransklaver@gmail.com" , "wsa@the-dreams.de" , "ron@debian.org" , "baruch@tkos.co.il" , "boris.brezillon@free-electrons.com" , "ezequiel.garcia@free-electrons.com" , "zajec5@gmail.com" , "kdasu.kdev@gmail.com" , "rogerq@ti.com" , bpqw , "asierra@xes-inc.com" CC: "linux-mtd@lists.infradead.org" , "linux-kernel@vger.kernel.org" Subject: [PATCH 6/6] mtd: nand: make new BBT work Thread-Topic: [PATCH 6/6] mtd: nand: make new BBT work Thread-Index: AdB36LBkNaa9p15cRCiFPwJ5GhrPXgAArWUQ Date: Thu, 16 Apr 2015 02:19:00 +0000 Message-ID: <87F60714EC601C4C83DFF1D2E3D390A0272825A1@NTXXIAMBX02.xacn.micron.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.167.84.5] X-TM-AS-Product-Ver: SMEX-10.0.0.4152-7.000.1014-21480.003 X-TM-AS-Result: No--10.811700-0.000000-31 X-TM-AS-User-Approved-Sender: Yes X-TM-AS-User-Blocked-Sender: No x-mt-checkinternalsenderrule: True Content-Type: text/plain; charset="gb2312" MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by nfs id t3G2K2QU019256 Content-Length: 10796 Lines: 308 Continue with Brain Norris's work. Allocate and initialize struct nand_bbt in nand_default_bbt()(nand_base.c). Remove .bbt from nand_chip. Complete hook nand_is_bad_bbm(nand_bbt.is_bad_bbm). Allocate and initialize badblock_pattern in nand_chip if badblock_pattern does not exist. And clean some checkpatch warnings. TBD: Allocate badblock_pattern is a temporary way to make new BBT work. Remove .badblock_pattern from struct nand_chip and use .badblockpos, .bbt_options and .options instead is the next thing to do. Signed-off-by: Peter Pan --- drivers/mtd/nand/diskonchip.c | 3 +- drivers/mtd/nand/docg4.c | 5 ++- drivers/mtd/nand/nand_base.c | 100 ++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/nand_bbt.c | 16 ++++--- include/linux/mtd/nand.h | 1 - include/linux/mtd/nand_bbt.h | 8 +++- 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e580014..b980d77 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1613,7 +1613,8 @@ static int __init doc_probe(unsigned long physadr) else numchips = doc2001_init(mtd); - if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) { + if ((ret = nand_scan(mtd, numchips)) + || (ret = doc->late_init(mtd))) { /* DBB note: i believe nand_release is necessary here, as buffers may have been allocated in nand_base. Check with Thomas. FIX ME! */ diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 9b671b9..5ed7c7c 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -1037,7 +1037,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd) * operation after device power-up. The above read ensures it never is. * Ugly, I know. */ - if (nand->bbt == NULL) /* no memory-based bbt */ + if (nand->nand_bbt == NULL) /* no memory-based bbt */ goto exit; if (mtd->ecc_stats.failed > eccfailed_stats) { @@ -1064,7 +1064,8 @@ static int __init read_factory_bbt(struct mtd_info *mtd) unsigned long bits = ~buf[i]; for_each_set_bit(bitnum, &bits, 8) { int badblock = block + 7 - bitnum; - nand_bbt_markbad(nand->nand_bbt, badblock << nand->bbt_erase_shift); + nand_bbt_markbad(nand->nand_bbt, badblock + << nand->bbt_erase_shift); mtd->ecc_stats.badblocks++; dev_notice(doc->dev, "factory-marked bad block: %d\n", badblock); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ff9db05..dbd9955 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -98,9 +98,13 @@ static int nand_get_device(struct mtd_info *mtd, int new_state); static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops); +static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); + static int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +static int nand_bbt_erase_block(struct mtd_info *mtd, loff_t addr); /* * For devices which display every fart in the system on a separate LED. Is * compiled away when LED support is disabled. @@ -531,13 +535,102 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, return nand_bbt_isreserved(bbt, ofs); } +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) +/** + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @chip: NAND chip to create descriptor for + * + * This function allocates and initializes a nand_bbt_descr for BBM detection + * based on the properties of @this. The new descriptor is stored in + * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when + * passed to this function. + */ +static int nand_create_badblock_pattern(struct nand_chip *chip) +{ + struct nand_bbt_descr *bd; + + if (chip->badblock_pattern) { + pr_warn("Bad block pattern already allocated; not replacing\n"); + return -EINVAL; + } + bd = kzalloc(sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + bd->options = chip->bbt_options & BADBLOCK_SCAN_MASK; + bd->offs = chip->badblockpos; + bd->len = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + bd->pattern = scan_ff_pattern; + bd->options |= NAND_BBT_DYNAMICSTRUCT; + chip->badblock_pattern = bd; + + return 0; +} + +static int nand_is_bad_bbm(struct mtd_info *mtd, loff_t addr) +{ + struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; + struct nand_bbt_descr *bd = chip->badblock_pattern; + int j, ret; + int numpages; + + if (bd->options & NAND_BBT_SCAN2NDPAGE) + numpages = 2; + else + numpages = 1; + + ops.ooblen = mtd->oobsize; + ops.oobbuf = chip->buffers->databuf; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + + for (j = 0; j < numpages; j++) { + /* + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. + */ + ret = nand_do_read_oob(mtd, addr, &ops); + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) + return ret; + + if (memcmp(chip->buffers->databuf + bd->offs, + bd->pattern, bd->len)) + return 1; + + addr += mtd->writesize; + } + + return 0; +} + static int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; + struct nand_bbt *bbt = kzalloc(sizeof(struct nand_bbt), GFP_KERNEL); + + if (!bbt) + return -ENOMEM; + + bbt->bbt_options = chip->bbt_options; + bbt->mtd = mtd; + bbt->numchips = chip->numchips; + bbt->chipsize = chip->chipsize; + bbt->chip_shift = chip->chip_shift; + bbt->bbt_erase_shift = chip->phys_erase_shift; + bbt->page_shift = chip->page_shift; + bbt->bbt_td = chip->bbt_td; + bbt->bbt_md = chip->bbt_md; + bbt->is_bad_bbm = nand_is_bad_bbm; + bbt->erase = nand_bbt_erase_block; + chip->nand_bbt = bbt; return nand_bbt_init(chip->nand_bbt); } + /** * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. * @mtd: MTD device structure @@ -4208,6 +4301,8 @@ int nand_scan_tail(struct mtd_info *mtd) if (chip->options & NAND_SKIP_BBTSCAN) return 0; + if (!chip->badblock_pattern && nand_create_badblock_pattern(chip)) + return -ENOMEM; /* Build bad block table */ return chip->scan_bbt(mtd); } @@ -4271,6 +4366,11 @@ void nand_release(struct mtd_info *mtd) kfree(chip->nand_bbt); if (!(chip->options & NAND_OWN_BUFFERS)) kfree(chip->buffers); + + /* Free bad block descriptor memory */ + if (chip->badblock_pattern && chip->badblock_pattern->options + & NAND_BBT_DYNAMICSTRUCT) + kfree(chip->badblock_pattern); } EXPORT_SYMBOL_GPL(nand_release); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 27269ea..ebbe6bf 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -245,7 +245,8 @@ static int read_bbt(struct nand_bbt *bbt, uint8_t *buf, int page, int num, * Read the bad block table for all chips starting at a given page. We assume * that the bbt bits are in consecutive order. */ -static int read_abs_bbt(struct nand_bbt *bbt, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt(struct nand_bbt *bbt, uint8_t *buf, + struct nand_bbt_descr *td, int chip) { struct mtd_info *mtd = bbt->mtd; int res = 0, i; @@ -398,14 +399,13 @@ static void read_abs_bbts(struct nand_bbt *bbt, uint8_t *buf, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @bbt: NAND BBT structure - * @buf: temporary buffer * @chip: create the table for a specific chip, -1 read all chips; applies only * if NAND_BBT_PERCHIP option is set * * Create a bad block table by scanning the device for the given good/bad block * identify pattern. */ -static int create_bbt(struct nand_bbt *bbt, uint8_t *buf, int chip) +static int create_bbt(struct nand_bbt *bbt, int chip) { struct mtd_info *mtd = bbt->mtd; int i, startblock, numblocks; @@ -463,7 +463,8 @@ static int create_bbt(struct nand_bbt *bbt, uint8_t *buf, int chip) * * The bbt ident pattern resides in the oob area of the first page in a block. */ -static int search_bbt(struct nand_bbt *bbt, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt(struct nand_bbt *bbt, uint8_t *buf, + struct nand_bbt_descr *td) { struct mtd_info *mtd = bbt->mtd; int i, chips; @@ -755,7 +756,7 @@ static int write_bbt(struct nand_bbt *bbt, uint8_t *buf, */ static inline int nand_memory_bbt(struct nand_bbt *bbt) { - return create_bbt(bbt, NULL /* FIXME: this->buffers->databuf */, -1); + return create_bbt(bbt, -1); } /** @@ -827,7 +828,7 @@ static int check_create(struct nand_bbt *bbt, uint8_t *buf) /* Create the table in memory by scanning the chip(s) */ if (!(bbt->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(bbt, buf, chipsel); + create_bbt(bbt, chipsel); td->version[i] = 1; if (md) @@ -912,7 +913,8 @@ static void mark_bbt_region(struct nand_bbt *bbt, struct nand_bbt_descr *td) !(td->options & NAND_BBT_WRITE)) { if (td->pages[i] == -1) continue; - block = td->pages[i] >> (bbt->bbt_erase_shift - bbt->page_shift); + block = td->pages[i] >> + (bbt->bbt_erase_shift - bbt->page_shift); oldval = bbt_get_entry(bbt, block); bbt_mark_entry(bbt, block, BBT_BLOCK_RESERVED); if ((oldval != BBT_BLOCK_RESERVED) && diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 539c9bf..fc53882 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -712,7 +712,6 @@ struct nand_chip { struct nand_hw_control hwcontrol; struct nand_bbt *nand_bbt; - uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; diff --git a/include/linux/mtd/nand_bbt.h b/include/linux/mtd/nand_bbt.h index f776695..ed71e0e 100644 --- a/include/linux/mtd/nand_bbt.h +++ b/include/linux/mtd/nand_bbt.h @@ -83,7 +83,7 @@ struct nand_bbt_descr { * with NAND_BBT_CREATE. */ #define NAND_BBT_CREATE_EMPTY 0x00000400 -/* Write bbt if neccecary */ +/* Write bbt if necessary */ #define NAND_BBT_WRITE 0x00002000 /* Read and write back block contents when writing bbt */ #define NAND_BBT_SAVECONTENT 0x00004000 @@ -107,6 +107,12 @@ struct nand_bbt_descr { */ #define NAND_BBT_NO_OOB_BBM 0x00080000 +/* + * Flag to mark that the nand_bbt_descr was allocated dynamicaly and must + * be freed in nand_release(). + */ +#define NAND_BBT_DYNAMICSTRUCT 0x80000000 + /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 -- 1.9.1 ????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?