From 31b6cfb28890071acc0c044abf9c48843e4100ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 17:27:29 +0100 Subject: [PATCH] kernel: mtk_bmt: extend debug interface Add support for showing remapped blocks and garbage collecting old remapped blocks triggered by using the mark_good/mark_bad files Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 2db31fe066b..cb74b4d10f1 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -672,8 +672,103 @@ static int mtk_bmt_debug_mark_bad(void *data, u64 val) return 0; } +static unsigned long * +mtk_bmt_get_mapping_mask(void) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + int main_blocks = bmtd.mtd->size >> bmtd.blk_shift; + unsigned long *used; + int i, k; + + used = kcalloc(sizeof(unsigned long), BIT_WORD(bmtd.bmt_blk_idx) + 1, GFP_KERNEL); + if (!used) + return NULL; + + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + for (k = 0; k < bmtd.bmt_blk_idx; k++) { + if (bmtd.bbt->bb_tbl[i] != bbmt[k].block) + continue; + + set_bit(k, used); + break; + } + } + + return used; +} + +static int mtk_bmt_debug(void *data, u64 val) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + struct mtd_info *mtd = bmtd.mtd; + unsigned long *used; + int main_blocks = mtd->size >> bmtd.blk_shift; + int n_remap = 0; + int i; + + used = mtk_bmt_get_mapping_mask(); + if (!used) + return -ENOMEM; + + switch (val) { + case 0: + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + printk("remap [%x->%x]\n", i, bmtd.bbt->bb_tbl[i]); + n_remap++; + } + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + char c; + + switch (bbmt[i].mapped) { + case NO_MAPPED: + continue; + case NORMAL_MAPPED: + c = 'm'; + if (test_bit(i, used)) + c = 'M'; + break; + case BMT_MAPPED: + c = 'B'; + break; + default: + c = 'X'; + break; + } + printk("[%x:%c] = 0x%x\n", i, c, bbmt[i].block); + } + break; + case 100: + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + if (bbmt[i].mapped != NORMAL_MAPPED) + continue; + + if (test_bit(i, used)) + continue; + + n_remap++; + bbmt[i].mapped = NO_MAPPED; + printk("free block [%d:%x]\n", i, bbmt[i].block); + } + if (n_remap) + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + break; + } + + kfree(used); + + return 0; +} + + 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"); static void mtk_bmt_add_debugfs(void) @@ -686,6 +781,7 @@ mtk_bmt_add_debugfs(void) 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); } void mtk_bmt_detach(struct mtd_info *mtd)