/** * nanddev_isbad() - Check if a block is bad * @nand: NAND device * @pos: position pointing to the block we want to check * * Return: true if the block is bad, false otherwise.
*/ bool nanddev_isbad(struct nand_device *nand, conststruct nand_pos *pos)
{ if (mtd_check_expert_analysis_mode()) returnfalse;
if (nanddev_bbt_is_initialized(nand)) { unsignedint entry; int status;
entry = nanddev_bbt_pos_to_entry(nand, pos);
status = nanddev_bbt_get_block_status(nand, entry); /* Lazy block status retrieval */ if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) { if (nand->ops->isbad(nand, pos))
status = NAND_BBT_BLOCK_FACTORY_BAD; else
status = NAND_BBT_BLOCK_GOOD;
/** * nanddev_markbad() - Mark a block as bad * @nand: NAND device * @pos: position of the block to mark bad * * Mark a block bad. This function is updating the BBT if available and * calls the low-level markbad hook (nand->ops->markbad()). * * Return: 0 in case of success, a negative error code otherwise.
*/ int nanddev_markbad(struct nand_device *nand, conststruct nand_pos *pos)
{ struct mtd_info *mtd = nanddev_to_mtd(nand); unsignedint entry; int ret = 0;
if (nanddev_isbad(nand, pos)) return 0;
ret = nand->ops->markbad(nand, pos); if (ret)
pr_warn("failed to write BBM to block @%llx (err = %d)\n",
nanddev_pos_to_offs(nand, pos), ret);
if (!nanddev_bbt_is_initialized(nand)) goto out;
entry = nanddev_bbt_pos_to_entry(nand, pos);
ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN); if (ret) goto out;
ret = nanddev_bbt_update(nand);
out: if (!ret)
mtd->ecc_stats.badblocks++;
return ret;
}
EXPORT_SYMBOL_GPL(nanddev_markbad);
/** * nanddev_isreserved() - Check whether an eraseblock is reserved or not * @nand: NAND device * @pos: NAND position to test * * Checks whether the eraseblock pointed by @pos is reserved or not. * * Return: true if the eraseblock is reserved, false otherwise.
*/ bool nanddev_isreserved(struct nand_device *nand, conststruct nand_pos *pos)
{ unsignedint entry; int status;
if (!nanddev_bbt_is_initialized(nand)) returnfalse;
/* Return info from the table */
entry = nanddev_bbt_pos_to_entry(nand, pos);
status = nanddev_bbt_get_block_status(nand, entry); return status == NAND_BBT_BLOCK_RESERVED;
}
EXPORT_SYMBOL_GPL(nanddev_isreserved);
/** * nanddev_erase() - Erase a NAND portion * @nand: NAND device * @pos: position of the block to erase * * Erases the block if it's not bad. * * Return: 0 in case of success, a negative error code otherwise.
*/ staticint nanddev_erase(struct nand_device *nand, conststruct nand_pos *pos)
{ if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
pr_warn("attempt to erase a bad/reserved block @%llx\n",
nanddev_pos_to_offs(nand, pos)); return -EIO;
}
return nand->ops->erase(nand, pos);
}
/** * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices * @mtd: MTD device * @einfo: erase request * * This is a simple mtd->_erase() implementation iterating over all blocks * concerned by @einfo and calling nand->ops->erase() on each of them. * * Note that mtd->_erase should not be directly assigned to this helper, * because there's no locking here. NAND specialized layers should instead * implement there own wrapper around nanddev_mtd_erase() taking the * appropriate lock before calling nanddev_mtd_erase(). * * Return: 0 in case of success, a negative error code otherwise.
*/ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
{ struct nand_device *nand = mtd_to_nanddev(mtd); struct nand_pos pos, last; int ret;
nanddev_offs_to_pos(nand, einfo->addr, &pos);
nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last); while (nanddev_pos_cmp(&pos, &last) <= 0) {
ret = nanddev_erase(nand, &pos); if (ret) {
einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
return ret;
}
nanddev_pos_next_eraseblock(nand, &pos);
}
return 0;
}
EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
/** * nanddev_mtd_max_bad_blocks() - Get the maximum number of bad eraseblock on * a specific region of the NAND device * @mtd: MTD device * @offs: offset of the NAND region * @len: length of the NAND region * * Default implementation for mtd->_max_bad_blocks(). Only works if * nand->memorg.max_bad_eraseblocks_per_lun is > 0. * * Return: a positive number encoding the maximum number of eraseblocks on a * portion of memory, a negative error code otherwise.
*/ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
{ struct nand_device *nand = mtd_to_nanddev(mtd); struct nand_pos pos, end; unsignedint max_bb = 0;
if (!nand->memorg.max_bad_eraseblocks_per_lun) return -ENOTSUPP;
ret = nand_ecc_init_ctx(nand); if (ret) return ret;
if (!nand_ecc_is_strong_enough(nand))
pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
nand->mtd.name);
return 0;
}
/** * nanddev_ecc_engine_init() - Initialize an ECC engine for the chip * @nand: NAND device
*/ int nanddev_ecc_engine_init(struct nand_device *nand)
{ int ret;
/* Look for the ECC engine to use */
ret = nanddev_get_ecc_engine(nand); if (ret) { if (ret != -EPROBE_DEFER)
pr_err("No ECC engine found\n");
return ret;
}
/* No ECC engine requested */ if (!nand->ecc.engine) return 0;
/* Configure the engine: balance user input and chip requirements */
ret = nanddev_find_ecc_configuration(nand); if (ret) {
pr_err("No suitable ECC configuration\n");
nanddev_put_ecc_engine(nand);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.