diff options
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/raw/nand_base.c | 324 |
1 files changed, 202 insertions, 122 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index ddd396e93e32..2cf71060d6f8 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -240,10 +240,10 @@ static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len) void nand_select_target(struct nand_chip *chip, unsigned int cs) { /* - * cs should always lie between 0 and chip->numchips, when that's not - * the case it's a bug and the caller should be fixed. + * cs should always lie between 0 and nanddev_ntargets(), when that's + * not the case it's a bug and the caller should be fixed. */ - if (WARN_ON(cs > chip->numchips)) + if (WARN_ON(cs > nanddev_ntargets(&chip->base))) return; chip->cur_cs = cs; @@ -283,6 +283,31 @@ static void nand_release_device(struct nand_chip *chip) } /** + * nand_bbm_get_next_page - Get the next page for bad block markers + * @chip: NAND chip object + * @page: First page to start checking for bad block marker usage + * + * Returns an integer that corresponds to the page offset within a block, for + * a page that is used to store bad block markers. If no more pages are + * available, -EINVAL is returned. + */ +int nand_bbm_get_next_page(struct nand_chip *chip, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int last_page = ((mtd->erasesize - mtd->writesize) >> + chip->page_shift) & chip->pagemask; + + if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE) + return 0; + else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE) + return 1; + else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE) + return last_page; + + return -EINVAL; +} + +/** * nand_block_bad - [DEFAULT] Read bad block marker from the chip * @chip: NAND chip object * @ofs: offset from device start @@ -291,18 +316,15 @@ static void nand_release_device(struct nand_chip *chip) */ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) { - struct mtd_info *mtd = nand_to_mtd(chip); - int page, page_end, res; + int first_page, page_offset; + int res; u8 bad; - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1); + first_page = (int)(ofs >> chip->page_shift) & chip->pagemask; + page_offset = nand_bbm_get_next_page(chip, 0); - for (; page < page_end; page++) { - res = chip->ecc.read_oob(chip, page); + while (page_offset >= 0) { + res = chip->ecc.read_oob(chip, first_page + page_offset); if (res < 0) return res; @@ -314,6 +336,8 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) res = hweight8(bad) < chip->badblockbits; if (res) return res; + + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); } return 0; @@ -459,8 +483,8 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, } /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; + if (page == chip->pagecache.page) + chip->pagecache.page = -1; nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); @@ -493,7 +517,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_ops ops; uint8_t buf[2] = { 0, 0 }; - int ret = 0, res, i = 0; + int ret = 0, res, page_offset; memset(&ops, 0, sizeof(ops)); ops.oobbuf = buf; @@ -506,17 +530,18 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) } ops.mode = MTD_OPS_PLACE_OOB; - /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - do { - res = nand_do_write_oob(chip, ofs, &ops); + page_offset = nand_bbm_get_next_page(chip, 0); + + while (page_offset >= 0) { + res = nand_do_write_oob(chip, + ofs + (page_offset * mtd->writesize), + &ops); + if (!ret) ret = res; - i++; - ofs += mtd->writesize; - } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + page_offset = nand_bbm_get_next_page(chip, page_offset + 1); + } return ret; } @@ -3173,7 +3198,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, use_bufpoi = 0; /* Is the current page in the buffer? */ - if (realpage != chip->pagebuf || oob) { + if (realpage != chip->pagecache.page || oob) { bufpoi = use_bufpoi ? chip->data_buf : buf; if (use_bufpoi && aligned) @@ -3199,7 +3224,7 @@ read_retry: if (ret < 0) { if (use_bufpoi) /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; break; } @@ -3208,11 +3233,11 @@ read_retry: if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && !(mtd->ecc_stats.failed - ecc_failures) && (ops->mode != MTD_OPS_RAW)) { - chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; + chip->pagecache.page = realpage; + chip->pagecache.bitflips = ret; } else { /* Invalidate page cache */ - chip->pagebuf = -1; + chip->pagecache.page = -1; } memcpy(buf, chip->data_buf + col, bytes); } @@ -3252,7 +3277,7 @@ read_retry: memcpy(buf, chip->data_buf + col, bytes); buf += bytes; max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); + chip->pagecache.bitflips); } readlen -= bytes; @@ -3973,9 +3998,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, page = realpage & chip->pagemask; /* Invalidate the page cache, when we write to the cached page */ - if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && - ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) - chip->pagebuf = -1; + if (to <= ((loff_t)chip->pagecache.page << chip->page_shift) && + ((loff_t)chip->pagecache.page << chip->page_shift) < (to + ops->len)) + chip->pagecache.page = -1; /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { @@ -4004,10 +4029,9 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, __func__, buf); if (part_pagewr) bytes = min_t(int, bytes - column, writelen); - chip->pagebuf = -1; - memset(chip->data_buf, 0xff, mtd->writesize); - memcpy(&chip->data_buf[column], buf, bytes); - wbuf = chip->data_buf; + wbuf = nand_get_data_buf(chip); + memset(wbuf, 0xff, mtd->writesize); + memcpy(&wbuf[column], buf, bytes); } if (unlikely(oob)) { @@ -4197,9 +4221,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, * Invalidate the page cache, if we erase the block which * contains the current cached page. */ - if (page <= chip->pagebuf && chip->pagebuf < + if (page <= chip->pagecache.page && chip->pagecache.page < (page + pages_per_block)) - chip->pagebuf = -1; + chip->pagecache.page = -1; ret = nand_erase_op(chip, (page & chip->pagemask) >> (chip->phys_erase_shift - chip->page_shift)); @@ -4299,42 +4323,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) } /** - * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd - * @mtd: MTD device structure - * @ofs: offset relative to mtd start - * @len: length of mtd - */ -static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 part_start_block; - u32 part_end_block; - u32 part_start_die; - u32 part_end_die; - - /* - * max_bb_per_die and blocks_per_die used to determine - * the maximum bad block count. - */ - if (!chip->max_bb_per_die || !chip->blocks_per_die) - return -ENOTSUPP; - - /* Get the start and end of the partition in erase blocks. */ - part_start_block = mtd_div_by_eb(ofs, mtd); - part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1; - - /* Get the start and end LUNs of the partition. */ - part_start_die = part_start_block / chip->blocks_per_die; - part_end_die = part_end_block / chip->blocks_per_die; - - /* - * Look up the bad blocks per unit and multiply by the number of units - * that the partition spans. - */ - return chip->max_bb_per_die * (part_end_die - part_start_die + 1); -} - -/** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd: MTD device structure */ @@ -4485,21 +4473,29 @@ static int nand_get_bits_per_cell(u8 cellinfo) */ void nand_decode_ext_id(struct nand_chip *chip) { + struct nand_memory_organization *memorg; struct mtd_info *mtd = nand_to_mtd(chip); int extid; u8 *id_data = chip->id.data; + + memorg = nanddev_get_memorg(&chip->base); + /* The 3rd id byte holds MLC / multichip data */ - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); /* The 4th id byte is the important one */ extid = id_data[3]; /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x03); + memorg->pagesize = 1024 << (extid & 0x03); + mtd->writesize = memorg->pagesize; extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + memorg->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + mtd->oobsize = memorg->oobsize; extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ + memorg->pages_per_eraseblock = ((64 * 1024) << (extid & 0x03)) / + memorg->pagesize; mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ @@ -4516,13 +4512,19 @@ EXPORT_SYMBOL_GPL(nand_decode_ext_id); static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + memorg->pages_per_eraseblock = type->erasesize / type->pagesize; mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->oobsize = memorg->pagesize / 32; + mtd->oobsize = memorg->oobsize; /* All legacy ID NAND are small-page, SLC */ - chip->bits_per_cell = 1; + memorg->bits_per_cell = 1; } /* @@ -4536,9 +4538,9 @@ static void nand_decode_bbm_options(struct nand_chip *chip) /* Set the bad block position */ if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + chip->badblockpos = NAND_BBM_POS_LARGE; else - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + chip->badblockpos = NAND_BBM_POS_SMALL; } static inline bool is_full_id_nand(struct nand_flash_dev *type) @@ -4550,18 +4552,28 @@ static bool find_full_id_nand(struct nand_chip *chip, struct nand_flash_dev *type) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; u8 *id_data = chip->id.data; + memorg = nanddev_get_memorg(&chip->base); + if (!strncmp(type->id, id_data, type->id_len)) { - mtd->writesize = type->pagesize; + memorg->pagesize = type->pagesize; + mtd->writesize = memorg->pagesize; + memorg->pages_per_eraseblock = type->erasesize / + type->pagesize; mtd->erasesize = type->erasesize; - mtd->oobsize = type->oobsize; - - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->chipsize = (uint64_t)type->chipsize << 20; + memorg->oobsize = type->oobsize; + mtd->oobsize = memorg->oobsize; + + memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); chip->options |= type->options; - chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); - chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->base.eccreq.strength = NAND_ECC_STRENGTH(type); + chip->base.eccreq.step_size = NAND_ECC_STEP(type); chip->onfi_timing_mode_default = type->onfi_timing_mode_default; @@ -4587,8 +4599,12 @@ static void nand_manufacturer_detect(struct nand_chip *chip) */ if (chip->manufacturer.desc && chip->manufacturer.desc->ops && chip->manufacturer.desc->ops->detect) { + struct nand_memory_organization *memorg; + + memorg = nanddev_get_memorg(&chip->base); + /* The 3rd id byte holds MLC / multichip data */ - chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); + memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->manufacturer.desc->ops->detect(chip); } else { nand_decode_ext_id(chip); @@ -4637,9 +4653,20 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) { const struct nand_manufacturer *manufacturer; struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; int busw, ret; u8 *id_data = chip->id.data; u8 maf_id, dev_id; + u64 targetsize; + + /* + * Let's start by initializing memorg fields that might be left + * unassigned by the ID-based detection logic. + */ + memorg = nanddev_get_memorg(&chip->base); + memorg->planes_per_lun = 1; + memorg->luns_per_target = 1; + memorg->ntargets = 1; /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) @@ -4735,8 +4762,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) if (!chip->parameters.model) return -ENOMEM; - chip->chipsize = (uint64_t)type->chipsize << 20; - if (!type->pagesize) nand_manufacturer_detect(chip); else @@ -4745,6 +4770,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) /* Get chip options */ chip->options |= type->options; + memorg->eraseblocks_per_lun = + DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20, + memorg->pagesize * + memorg->pages_per_eraseblock); + ident_done: if (!mtd->name) mtd->name = chip->parameters.model; @@ -4773,14 +4803,15 @@ ident_done: /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + targetsize = nanddev_target_size(&chip->base); + chip->pagemask = (targetsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + if (targetsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)targetsize) - 1; else { - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift = ffs((unsigned)(targetsize >> 32)); chip->chip_shift += 32 - 1; } @@ -4796,7 +4827,7 @@ ident_done: pr_info("%s %s\n", nand_manufacturer_name(manufacturer), chip->parameters.model); pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", - (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", + (int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); return 0; @@ -4971,10 +5002,13 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *table) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg; int nand_maf_id, nand_dev_id; unsigned int i; int ret; + memorg = nanddev_get_memorg(&chip->base); + /* Assume all dies are deselected when we enter nand_scan_ident(). */ chip->cur_cs = -1; @@ -4990,12 +5024,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, if (!mtd->name && mtd->dev.parent) mtd->name = dev_name(mtd->dev.parent); - /* - * Start with chips->numchips = maxchips to let nand_select_target() do - * its job. chip->numchips will be adjusted after. - */ - chip->numchips = maxchips; - /* Set the default functions */ nand_set_defaults(chip); @@ -5042,8 +5070,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, pr_info("%d chips detected\n", i); /* Store the number of chips and calc total size for mtd */ - chip->numchips = i; - mtd->size = i * chip->chipsize; + memorg->ntargets = i; + mtd->size = i * nanddev_target_size(&chip->base); return 0; } @@ -5078,13 +5106,13 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) ecc->bytes = 3; ecc->strength = 1; - if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) + if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; return 0; case NAND_ECC_BCH: if (!mtd_nand_has_bch()) { - WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + WARN(1, "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n"); return -EINVAL; } ecc->calculate = nand_bch_calculate_ecc; @@ -5224,8 +5252,8 @@ nand_match_ecc_req(struct nand_chip *chip, { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_ecc_step_info *stepinfo; - int req_step = chip->ecc_step_ds; - int req_strength = chip->ecc_strength_ds; + int req_step = chip->base.eccreq.step_size; + int req_strength = chip->base.eccreq.strength; int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; int best_step, best_strength, best_ecc_bytes; int best_ecc_bytes_total = INT_MAX; @@ -5418,7 +5446,7 @@ static bool nand_ecc_strength_good(struct nand_chip *chip) struct nand_ecc_ctrl *ecc = &chip->ecc; int corr, ds_corr; - if (ecc->size == 0 || chip->ecc_step_ds == 0) + if (ecc->size == 0 || chip->base.eccreq.step_size == 0) /* Not enough information */ return true; @@ -5427,11 +5455,56 @@ static bool nand_ecc_strength_good(struct nand_chip *chip) * the correction density. */ corr = (mtd->writesize * ecc->strength) / ecc->size; - ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds; + ds_corr = (mtd->writesize * chip->base.eccreq.strength) / + chip->base.eccreq.step_size; - return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; + return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength; } +static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + unsigned int eb = nanddev_pos_to_row(nand, pos); + int ret; + + eb >>= nand->rowconv.eraseblock_addr_shift; + + nand_select_target(chip, pos->target); + ret = nand_erase_op(chip, eb); + nand_deselect_target(chip); + + return ret; +} + +static int rawnand_markbad(struct nand_device *nand, + const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + + return nand_markbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); +} + +static bool rawnand_isbad(struct nand_device *nand, const struct nand_pos *pos) +{ + struct nand_chip *chip = container_of(nand, struct nand_chip, + base); + int ret; + + nand_select_target(chip, pos->target); + ret = nand_isbad_bbm(chip, nanddev_pos_to_offs(nand, pos)); + nand_deselect_target(chip); + + return ret; +} + +static const struct nand_ops rawnand_ops = { + .erase = rawnand_erase, + .markbad = rawnand_markbad, + .isbad = rawnand_isbad, +}; + /** * nand_scan_tail - Scan for the NAND device * @chip: NAND chip object @@ -5687,7 +5760,7 @@ static int nand_scan_tail(struct nand_chip *chip) chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; + chip->pagecache.page = -1; /* Large page NAND with SOFT_ECC should support subpage reads */ switch (ecc->mode) { @@ -5700,10 +5773,15 @@ static int nand_scan_tail(struct nand_chip *chip) break; } + ret = nanddev_init(&chip->base, &rawnand_ops, mtd->owner); + if (ret) + goto err_nand_manuf_cleanup; + + /* Adjust the MTD_CAP_ flags when NAND_ROM is set. */ + if (chip->options & NAND_ROM) + mtd->flags = MTD_CAP_ROM; + /* Fill in remaining MTD driver data */ - mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; - mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : - MTD_CAP_NANDFLASH; mtd->_erase = nand_erase; mtd->_point = NULL; mtd->_unpoint = NULL; @@ -5719,8 +5797,7 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->_block_isreserved = nand_block_isreserved; mtd->_block_isbad = nand_block_isbad; mtd->_block_markbad = nand_block_markbad; - mtd->_max_bad_blocks = nand_max_bad_blocks; - mtd->writebufsize = mtd->writesize; + mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; /* * Initialize bitflip_threshold to its default prior scan_bbt() call. @@ -5733,13 +5810,13 @@ static int nand_scan_tail(struct nand_chip *chip) /* Initialize the ->data_interface field. */ ret = nand_init_data_interface(chip); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; /* Enter fastest possible mode on all dies. */ - for (i = 0; i < chip->numchips; i++) { + for (i = 0; i < nanddev_ntargets(&chip->base); i++) { ret = nand_setup_data_interface(chip, i); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; } /* Check, if we should skip the bad block table scan */ @@ -5749,11 +5826,14 @@ static int nand_scan_tail(struct nand_chip *chip) /* Build bad block table */ ret = nand_create_bbt(chip); if (ret) - goto err_nand_manuf_cleanup; + goto err_nanddev_cleanup; return 0; +err_nanddev_cleanup: + nanddev_cleanup(&chip->base); + err_nand_manuf_cleanup: nand_manufacturer_cleanup(chip); |