--- zzzz-none-000/linux-3.10.107/drivers/mtd/mtdcore.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/drivers/mtd/mtdcore.c 2021-11-10 11:53:55.000000000 +0000 @@ -257,6 +257,47 @@ } static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); +static ssize_t mtd_ecc_stats_corrected_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; + + return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->corrected); +} +static DEVICE_ATTR(corrected_bits, S_IRUGO, + mtd_ecc_stats_corrected_show, NULL); + +static ssize_t mtd_ecc_stats_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; + + return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->failed); +} +static DEVICE_ATTR(ecc_failures, S_IRUGO, mtd_ecc_stats_errors_show, NULL); + +static ssize_t mtd_badblocks_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; + + return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->badblocks); +} +static DEVICE_ATTR(bad_blocks, S_IRUGO, mtd_badblocks_show, NULL); + +static ssize_t mtd_bbtblocks_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats; + + return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->bbtblocks); +} +static DEVICE_ATTR(bbt_blocks, S_IRUGO, mtd_bbtblocks_show, NULL); + static ssize_t mtd_bitflip_threshold_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -296,6 +337,10 @@ &dev_attr_numeraseregions.attr, &dev_attr_name.attr, &dev_attr_ecc_strength.attr, + &dev_attr_corrected_bits.attr, + &dev_attr_ecc_failures.attr, + &dev_attr_bad_blocks.attr, + &dev_attr_bbt_blocks.attr, &dev_attr_bitflip_threshold.attr, NULL, }; @@ -806,10 +851,12 @@ * any one ecc region (if applicable; zero otherwise). */ ret_code = mtd->_read(mtd, from, len, retlen, buf); - if (unlikely(ret_code < 0)) + if (unlikely(ret_code < 0)) { return ret_code; - if (mtd->ecc_strength == 0) + } + if (mtd->ecc_strength == 0) { return 0; /* device lacks ecc */ + } return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; } EXPORT_SYMBOL_GPL(mtd_read); @@ -1134,12 +1181,292 @@ return single_open(file, mtd_proc_show, NULL); } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +static struct semaphore erase_lock_sema; + +static void mtd_erase_block_done(struct erase_info *self) { + up(&erase_lock_sema); + + if (self->state != MTD_ERASE_DONE) { + printk("[MTD%d]: callback erase failed on 0x%llu\n", self->mtd->index, self->fail_addr); + } +} + +static int mtd_erase_block(struct mtd_info *mtd, unsigned int addr, unsigned int len, unsigned int force) { + static struct erase_info erase; + memset(&erase, 0, sizeof(erase)); + erase.mtd = mtd; + erase.addr = addr; + erase.len = len; + erase.retries = 1; + erase.callback = mtd_erase_block_done; + + if (force) { + erase.priv = 1; /*--- signal force to mtd->erase ---*/ + } + + if(down_interruptible(&erase_lock_sema)) { + printk("[MTD%d]: wait for erase failed\n", mtd->index); + return -EFAULT; + } + + if(mtd->_erase(mtd, &erase)) { + printk("[MTD%d]: setup erase failed\n", mtd->index); + up(&erase_lock_sema); + return -EFAULT; + } + + return erase.state == MTD_ERASE_DONE ? 0 : -EFAULT; +} + +static void mtd_read_block(struct mtd_info *mtd, unsigned int addr, unsigned int len, char *buf) { + size_t retlen; + + if(mtd->_read(mtd, addr, len, &retlen, buf)) { + printk(KERN_ERR "[MTD%d]: setup read failed\n", mtd->index); + return; + } + printk(KERN_ERR "[%s] %d, %d %d\n", __FUNCTION__, addr, len, retlen); +} + +static void mtd_write_block(struct mtd_info *mtd, unsigned int addr, unsigned int len, char *buf) { + size_t retlen; + + if(mtd->_write(mtd, addr, len, &retlen, (const u_char*)buf)) { + printk(KERN_ERR "[MTD%d]: setup write failed\n", mtd->index); + printk(KERN_ERR "[%s] %d, %d %d\n", __FUNCTION__, addr, len, retlen); + return; + } + printk(KERN_ERR "[%s] %d, %d %d\n", __FUNCTION__, addr, len, retlen); +} + +static ssize_t mtd_proc_write(struct file *filp, const char __user *buf, size_t count, + loff_t *offset __attribute__ ((unused))) +{ + int blocknr, num; + char *s, *ss, *end; + struct mtd_info *mtd; + if((s = strstr(buf, "mtd")) != NULL) { + + u_int32_t mtd_blockcount; + num = simple_strtoul(s + sizeof("mtd"), &end, 0); + + mtd = get_mtd_device(NULL, num); + /*----------------------------------------------------------------------------------*\ + \*----------------------------------------------------------------------------------*/ + if ( ! mtd) { + printk(KERN_ERR "[MTD]: mtd %d ist no valid MTD\n", num); + return count; + } + /*----------------------------------------------------------------------------------*\ + \*----------------------------------------------------------------------------------*/ + mtd_blockcount = (uint32_t)mtd->size / mtd->erasesize; + + printk(KERN_ERR "[MTD%d]: name = \"%s\"\n", num, mtd->name); + + sema_init (&erase_lock_sema, 1); + /*----------------------------------------------------------------------------------*\ + \*----------------------------------------------------------------------------------*/ + if((ss = strstr(s, "erase"))) { + unsigned int force = 0; + printk(KERN_ERR "[MTD%d]: erase: mtd size 0x%llx block size 0x%x erase block count 0x%x\n", + num, + mtd->size, + mtd->erasesize, + (uint32_t)mtd->size / mtd->erasesize); + if((s = strstr(ss, "all"))) { + if ((ss = strstr(s, "force"))) + force = 1; + printk(KERN_ERR "[MTD%d]: erase all blocks.\n", num); + for(blocknr = 0 ; blocknr < mtd_blockcount ; blocknr++) { + printk(KERN_ERR "[MTD%d]: erase block %d(0x%x) from %d(0x%x)\n", num, blocknr, blocknr, mtd_blockcount, mtd_blockcount); + mtd_erase_block(mtd, mtd->erasesize * blocknr, mtd->erasesize, force); + } + } else { + blocknr = simple_strtoul(ss + sizeof("erase"), &end, 0); + printk(KERN_ERR "[MTD%d]: erase block %d(0x%x)\n", num, blocknr, blocknr); + mtd_erase_block(mtd, mtd->erasesize * blocknr, mtd->erasesize, force); + } + put_mtd_device(mtd); + return count; + } +#if 0 + else if((ss = strstr(s, "write_pattern"))) { + static char my_buf[2112]; + int i; + for(i = 0; i < 2112; i++) + my_buf[i] = i&0xFF; + printk(KERN_ERR "[MTD%d]: write_pattern: mtd size 0x%llx block size 0x%x erase block count 0x%x\n", + num, + mtd->size, + mtd->erasesize, + (uint32_t)mtd->size / mtd->erasesize); + if((s = strstr(ss, "all"))) { + printk(KERN_ERR "[MTD%d]: write pattern to all blocks.\n", num); + for(blocknr = 0 ; blocknr < mtd_blockcount ; blocknr++) { + printk(KERN_ERR "[MTD%d]: write pattern to block %d(0x%x) from %d(0x%x)\n", num, blocknr, blocknr, mtd_blockcount, mtd_blockcount); + mtd_write_block(mtd, mtd->erasesize * blocknr, 2112, my_buf); + } + } else { + blocknr = simple_strtoul(ss + sizeof("write_pattern"), &end, 0); + printk(KERN_ERR "[MTD%d]: write pattern to block %d(0x%x)\n", num, blocknr, blocknr); + mtd_write_block(mtd, mtd->erasesize * blocknr, 2112, my_buf); + } + put_mtd_device(mtd); + return count; + } else if((ss = strstr(s, "verify_pattern"))) { + static char my_buf[2112]; + int i; + printk(KERN_ERR "[MTD%d]: verify_pattern: mtd size 0x%llx block size 0x%x erase block count 0x%x\n", + num, + mtd->size, + mtd->erasesize, + (uint32_t)mtd->size / mtd->erasesize); + if((s = strstr(ss, "all"))) { + printk(KERN_ERR "[MTD%d]: verify pattern of all blocks.\n", num); + for(blocknr = 0 ; blocknr < mtd_blockcount ; blocknr++) { + printk(KERN_ERR "[MTD%d]: verify pattern of block %d(0x%x) from %d(0x%x)\n", num, blocknr, blocknr, mtd_blockcount, mtd_blockcount); + mtd_read_block(mtd, mtd->erasesize * blocknr, 2112, my_buf); + for(i = 0; i < 2112; i++) { + char comp1, comp2; + comp1 = (my_buf[i])&0xFF; + comp2 = (char)(i&0xFF); + if(comp1 != comp2) { + printk("err %04d:%04d %02x (exp %02x)\n", blocknr, i, my_buf[i]&0xFF, i&0xFF); + } + } + } + } else { + blocknr = simple_strtoul(ss + sizeof("verify_pattern"), &end, 0); + printk(KERN_ERR "[MTD%d]: verify pattern of block %d(0x%x)\n", num, blocknr, blocknr); + mtd_read_block(mtd, mtd->erasesize * blocknr, 2112, my_buf); + for(i = 0; i < 2112; i++) { + char comp1, comp2; + comp1 = (my_buf[i])&0xFF; + comp2 = (char)(i&0xFF); + if(comp1 != comp2) { + printk("err %04d:%04d %02x (exp %02x)\n", blocknr, i, my_buf[i]&0xFF, i&0xFF); + } + } + } + put_mtd_device(mtd); + return count; + } else if((ss = strstr(s, "write"))) { + static char my_buf[2112]; + int i, block_no, page_no, offset; + for(i = 0; i < 2112; i++) { + my_buf[i] = i & 0xFF; + } + + /*--- printk(KERN_ERR "1: %s\n", ss); ---*/ + block_no = simple_strtoul( ss + sizeof("write"), &end, 0); + + /*--- printk(KERN_ERR "2: %s\n", end + 1); ---*/ + page_no = simple_strtoul(end + 1, &end, 0); + + /*--- printk(KERN_ERR "3: %s\n", end + 1); ---*/ + offset = simple_strtoul(end + 1, &end, 0); + + while(*end == ' ') { + end++; + } + memcpy(my_buf, end, count + (end - buf)); + + /*--- printk(KERN_ERR "%d, %d, %d, '%s'\n", block_no, page_no, offset, end); ---*/ + + mtd_write_block(mtd, mtd->erasesize * block_no + page_no * 2112 + offset, count + (end - buf), my_buf); + + put_mtd_device(mtd); + return count; + } else if((ss = strstr(s, "read"))) { + static char my_buf[2112]; + int i, block_no, page_no, offset, len; + for(i = 0; i < 2112; i++) { + my_buf[i] = i & 0xFF; + } + + /*--- printk(KERN_ERR "1: %s\n", ss); ---*/ + block_no = simple_strtoul( ss + sizeof("read"), &end, 0); + + /*--- printk(KERN_ERR "2: %s\n", end + 1); ---*/ + page_no = simple_strtoul(end + 1, &end, 0); + + /*--- printk(KERN_ERR "3: %s\n", end + 1); ---*/ + offset = simple_strtoul(end + 1, &end, 0); + + /*--- printk(KERN_ERR "4: %s\n", end + 1); ---*/ + len = simple_strtoul(end + 1, &end, 0); + + /*--- printk(KERN_ERR "%d, %d, %d, %d\n", block_no, page_no, offset, len); ---*/ + + mtd_read_block(mtd, mtd->erasesize * block_no + page_no * 2112 + offset, len, my_buf); + + for(i = 0; i < len; i++) { + printk("%02x ", my_buf[i] & 0xFF); + if(!(len%10)) + printk("\n"); + } + printk("\n"); + + put_mtd_device(mtd); + return count; + } +#endif + put_mtd_device(mtd); + } + + printk(KERN_ERR "[MTD]: mtd erase |all\n"); + /*--- printk(KERN_ERR "[MTD]: mtd write \n"); ---*/ + /*--- printk(KERN_ERR "[MTD]: mtd read \n"); ---*/ + return count; + +} + static const struct file_operations mtd_proc_ops = { .open = mtd_proc_open, + .write = mtd_proc_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; + +/*====================================================================*/ +/* Support for /proc/mtd */ +#if defined(CONFIG_AVM_ENHANCED) +static struct proc_dir_entry *proc_bbt_mtd; +static int mtd_bbt_proc_show(struct seq_file *m, void *v) +{ + struct mtd_info *mtd; + + mutex_lock(&mtd_table_mutex); + mtd_for_each_device(mtd) { + if (mtd->_block_isbad) { + uint64_t i; + unsigned int badblocks=0; + for (i = 0; i < mtd->size; i += mtd->erasesize) { + if (mtd->_block_isbad(mtd, i) && ((badblocks+1)>badblocks) ) + badblocks++; + } + seq_printf(m, "mtd%d: %u bad blocks\n", mtd->index, badblocks); + } + } + mutex_unlock(&mtd_table_mutex); + return 0; +} + +static int mtd_bbt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mtd_bbt_proc_show, NULL); +} + +static const struct file_operations mtd_bbt_proc_ops = { + .open = mtd_bbt_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /*--- #if #defined(CONFIG_AVM_ENHANCED) ---*/ #endif /* CONFIG_PROC_FS */ /*====================================================================*/ @@ -1183,6 +1510,10 @@ proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops); +#if defined(CONFIG_AVM_ENHANCED) + proc_bbt_mtd = proc_create("avm/mtd_bbt", 0, NULL, &mtd_bbt_proc_ops); +#endif + ret = init_mtdchar(); if (ret) goto out_procfs; @@ -1192,6 +1523,12 @@ out_procfs: if (proc_mtd) remove_proc_entry("mtd", NULL); + +#if defined(CONFIG_AVM_ENHANCED) + if (proc_bbt_mtd) + remove_proc_entry("mtd_bbt", NULL); +#endif + err_bdi3: bdi_destroy(&mtd_bdi_ro_mappable); err_bdi2: @@ -1208,6 +1545,12 @@ cleanup_mtdchar(); if (proc_mtd) remove_proc_entry("mtd", NULL); + +#if defined(CONFIG_AVM_ENHANCED) + if (proc_bbt_mtd) + remove_proc_entry("mtd_bbt", NULL); +#endif + class_unregister(&mtd_class); bdi_destroy(&mtd_bdi_unmappable); bdi_destroy(&mtd_bdi_ro_mappable);