return false;
}
+static bool
+mtk_bmt_remap_block(u32 block, u32 mapped_block, int copy_len)
+{
+ int start, end;
+
+ if (!mapping_block_in_range(block, &start, &end))
+ return false;
+
+ return bmtd.ops->remap_block(block, mapped_block, copy_len);
+}
+
static int
mtk_bmt_read(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
loff_t cur_from;
int ret = 0;
int max_bitflips = 0;
- int start, end;
ops->retlen = 0;
ops->oobretlen = 0;
else
max_bitflips = max_t(int, max_bitflips, cur_ret);
if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) {
- bmtd.ops->remap_block(block, cur_block, mtd->erasesize);
- if (retry_count++ < 10)
+ if (mtk_bmt_remap_block(block, cur_block, mtd->erasesize) &&
+ retry_count++ < 10)
continue;
goto out;
}
- if (cur_ret >= mtd->bitflip_threshold &&
- mapping_block_in_range(block, &start, &end))
- bmtd.ops->remap_block(block, cur_block, mtd->erasesize);
+ if (mtd->bitflip_threshold && cur_ret >= mtd->bitflip_threshold)
+ mtk_bmt_remap_block(block, cur_block, mtd->erasesize);
ops->retlen += cur_ops.retlen;
ops->oobretlen += cur_ops.oobretlen;
ops->len - ops->retlen);
ret = bmtd._write_oob(mtd, cur_to, &cur_ops);
if (ret < 0) {
- bmtd.ops->remap_block(block, cur_block, offset);
- if (retry_count++ < 10)
+ if (mtk_bmt_remap_block(block, cur_block, offset) &&
+ retry_count++ < 10)
continue;
return ret;
mapped_instr.addr = (loff_t)block << bmtd.blk_shift;
ret = bmtd._erase(mtd, &mapped_instr);
if (ret) {
- bmtd.ops->remap_block(orig_block, block, 0);
- if (retry_count++ < 10)
+ if (mtk_bmt_remap_block(orig_block, block, 0) &&
+ retry_count++ < 10)
continue;
instr->fail_addr = start_addr;
break;
block = bmtd.ops->get_mapping_block(orig_block);
ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift);
if (ret) {
- bmtd.ops->remap_block(orig_block, block, bmtd.blk_size);
- if (retry_count++ < 10)
+ if (mtk_bmt_remap_block(orig_block, block, bmtd.blk_size) &&
+ retry_count++ < 10)
goto retry;
}
return ret;
if (block < 0)
return -EIO;
- bmtd.ops->remap_block(orig_block, block, bmtd.blk_size);
+ mtk_bmt_remap_block(orig_block, block, bmtd.blk_size);
return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift);
}
mtd->_block_markbad = mtk_bmt_block_markbad;
}
+static int mtk_bmt_debug_repair(void *data, u64 val)
+{
+ int block = val >> bmtd.blk_shift;
+ int prev_block, new_block;
+
+ prev_block = bmtd.ops->get_mapping_block(block);
+ if (prev_block < 0)
+ return -EIO;
+
+ bmtd.ops->unmap_block(block);
+ new_block = bmtd.ops->get_mapping_block(block);
+ if (new_block < 0)
+ return -EIO;
+
+ if (prev_block == new_block)
+ return 0;
+
+ bbt_nand_erase(new_block);
+ bbt_nand_copy(new_block, prev_block, bmtd.blk_size);
+
+ return 0;
+}
+
static int mtk_bmt_debug_mark_good(void *data, u64 val)
{
- bmtd.ops->unmap_block(val >> bmtd.blk_shift);
+ bmtd.ops->unmap_block(val >> bmtd.blk_shift);
return 0;
}
if (cur_block < 0)
return -EIO;
- bmtd.ops->remap_block(block, cur_block, bmtd.blk_size);
+ mtk_bmt_remap_block(block, cur_block, bmtd.blk_size);
return 0;
}
}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_repair, NULL, mtk_bmt_debug_repair, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(fops_debug, NULL, mtk_bmt_debug, "%llu\n");
if (!dir)
return;
+ debugfs_create_file_unsafe("repair", S_IWUSR, dir, NULL, &fops_repair);
debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good);
debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad);
debugfs_create_file_unsafe("debug", S_IWUSR, dir, NULL, &fops_debug);
if (of_property_read_bool(np, "mediatek,bmt-v2"))
bmtd.ops = &mtk_bmt_v2_ops;
+ else if (of_property_read_bool(np, "mediatek,nmbm"))
+ bmtd.ops = &mtk_bmt_nmbm_ops;
else if (of_property_read_bool(np, "mediatek,bbt"))
bmtd.ops = &mtk_bmt_bbt_ops;
else
bmtd.pg_shift = ffs(bmtd.pg_size) - 1;
bmtd.total_blks = mtd->size >> bmtd.blk_shift;
- bmtd.data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL);
+ bmtd.data_buf = kzalloc(bmtd.pg_size + bmtd.mtd->oobsize, GFP_KERNEL);
if (!bmtd.data_buf) {
pr_info("nand: FATAL ERR: allocate buffer failed!\n");
ret = -1;
goto error;
}
- memset(bmtd.data_buf, 0xff, bmtd.pg_size);
+ memset(bmtd.data_buf, 0xff, bmtd.pg_size + bmtd.mtd->oobsize);
ret = bmtd.ops->init(np);
if (ret)