From 08fb3d0741fff02fa6486395244d0a029f63c284 Mon Sep 17 00:00:00 2001 From: Yonghui Yu Date: Wed, 14 Jun 2017 21:19:51 +0800 Subject: [PATCH] mtd: nand: enhance the robust of env PD#145594: nand: enhance the robust of env 1)enhance sudden power lost and ecc-error protection 2)add mtd env mutex for kernel Change-Id: I0a454149c408f882924543d84db5d46591230d3d Signed-off-by: Yonghui Yu --- drivers/amlogic/mtd/aml_env.c | 9 +++++++- drivers/amlogic/mtd/aml_mtd.h | 3 +++ drivers/amlogic/mtd/rsv_manage.c | 46 +++++++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/drivers/amlogic/mtd/aml_env.c b/drivers/amlogic/mtd/aml_env.c index 3ce02cd..8b993fb 100644 --- a/drivers/amlogic/mtd/aml_env.c +++ b/drivers/amlogic/mtd/aml_env.c @@ -22,6 +22,7 @@ #include #define ENV_NAME "nand_env" +static DEFINE_MUTEX(env_mutex); static dev_t uboot_env_no; struct cdev uboot_env; struct device *uboot_dev; @@ -151,12 +152,13 @@ ssize_t env_store(struct class *class, struct class_attribute *attr, int ret = 0; u8 *env_ptr = NULL; - pr_info("env_store : #####\n"); env_ptr = kzalloc(CONFIG_ENV_SIZE, GFP_KERNEL); if (env_ptr == NULL) return -ENOMEM; + mutex_lock(&env_mutex); + pr_info("env_store : #####\n"); ret = amlnf_env_read(env_ptr, CONFIG_ENV_SIZE); if (ret) { pr_info("nand_env_read: nand env read failed\n"); @@ -172,6 +174,7 @@ ssize_t env_store(struct class *class, struct class_attribute *attr, } pr_info("env_store : OK #####\n"); + mutex_unlock(&env_mutex); return count; } @@ -202,6 +205,7 @@ ssize_t uboot_env_read(struct file *file, env_ptr = vmalloc(CONFIG_ENV_SIZE + 2048); if (env_ptr == NULL) return -ENOMEM; + mutex_lock(&env_mutex); /*amlnand_get_device(aml_chip_env, CHIP_READING);*/ ret = amlnf_env_read((u8 *)env_ptr, CONFIG_ENV_SIZE); @@ -220,6 +224,7 @@ ssize_t uboot_env_read(struct file *file, ret = copy_to_user(buf, (env_ptr + *ppos), read_size); *ppos += read_size; exit: + mutex_unlock(&env_mutex); /*amlnand_release_device(aml_chip_env);*/ vfree(env_ptr); return read_size; @@ -245,6 +250,7 @@ ssize_t uboot_env_write(struct file *file, if (env_ptr == NULL) return -ENOMEM; + mutex_lock(&env_mutex); /*not need nand_get_device here, mtd->_read_xx will done with it*/ /*nand_get_device(mtd, FL_WRITING);*/ ret = amlnf_env_read((u8 *)env_ptr, CONFIG_ENV_SIZE); @@ -270,6 +276,7 @@ ssize_t uboot_env_write(struct file *file, *ppos += write_size; exit: + mutex_unlock(&env_mutex); /*nand_release_device(mtd);*/ vfree(env_ptr); return write_size; diff --git a/drivers/amlogic/mtd/aml_mtd.h b/drivers/amlogic/mtd/aml_mtd.h index 6e8c9fa..1ce7a4f 100644 --- a/drivers/amlogic/mtd/aml_mtd.h +++ b/drivers/amlogic/mtd/aml_mtd.h @@ -310,6 +310,9 @@ struct aml_nandrsv_info_t { u_char part_num_before_sys; }; +/*define abnormal state for reserved area*/ +#define POWER_ABNORMAL_FLAG 0x01 +#define ECC_ABNORMAL_FLAG 0x02 struct valid_node_t { int16_t ec; int16_t phy_blk_addr; diff --git a/drivers/amlogic/mtd/rsv_manage.c b/drivers/amlogic/mtd/rsv_manage.c index b5fb8e0..6f25978 100644 --- a/drivers/amlogic/mtd/rsv_manage.c +++ b/drivers/amlogic/mtd/rsv_manage.c @@ -82,36 +82,42 @@ static void release_free_node(struct mtd_info *mtd, int aml_nand_rsv_erase_protect(struct mtd_info *mtd, unsigned int block_addr) { struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + unsigned int bbt_start, bbt_end, key_start, key_end; if (!_aml_rsv_isprotect()) return 0; + bbt_start = aml_chip->aml_nandbbt_info->start_block; + bbt_end = aml_chip->aml_nandbbt_info->end_block; + key_start = aml_chip->aml_nandkey_info->start_block; + key_end = aml_chip->aml_nandkey_info->end_block; + #ifdef AML_NAND_UBOOT if (aml_chip->aml_nandkey_info != NULL) { if (aml_chip->aml_nandkey_info->valid) if ((!(info_disprotect & DISPROTECT_KEY)) - && ((block_addr >= aml_chip->aml_nandkey_info->start_block) - && (block_addr < aml_chip->aml_nandkey_info->end_block))) - return -1; /*need skip key blocks*/ + && ((block_addr >= key_start) + && (block_addr < key_end))) + return -1; /*need skip key blocks*/ } if (aml_chip->aml_nandbbt_info != NULL) { if (aml_chip->aml_nandbbt_info->valid) - if ((block_addr >= aml_chip->aml_nandbbt_info->start_block) - && (block_addr < aml_chip->aml_nandbbt_info->end_block)) - return -1; /*need skip bbt blocks*/ + if ((block_addr >= bbt_start) + && (block_addr < bbt_end)) + return -1; /*need skip bbt blocks*/ } #else if (aml_chip->aml_nandkey_info != NULL) { if (aml_chip->aml_nandkey_info->valid) - if ((block_addr >= aml_chip->aml_nandkey_info->start_block) - && (block_addr < aml_chip->aml_nandkey_info->end_block)) - return -1; /*need skip key blocks*/ + if ((block_addr >= key_start) + && (block_addr < key_end)) + return -1; /*need skip key blocks*/ } if (aml_chip->aml_nandbbt_info != NULL) { if (aml_chip->aml_nandbbt_info->valid) - if ((block_addr >= aml_chip->aml_nandbbt_info->start_block) - && (block_addr < aml_chip->aml_nandbbt_info->end_block)) - return -1; /*need skip bbt blocks*/ + if ((block_addr >= bbt_start) + && (block_addr < bbt_end)) + return -1; /*need skip bbt blocks*/ } #endif return 0; @@ -598,6 +604,11 @@ int aml_nand_save_rsv_info(struct mtd_info *mtd, struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); pages_per_blk = mtd->erasesize / mtd->writesize; + /*solve these abnormals caused by power off and ecc error*/ + if ((nandrsv_info->valid_node->status & POWER_ABNORMAL_FLAG) + || (nandrsv_info->valid_node->status & ECC_ABNORMAL_FLAG)) + nandrsv_info->valid_node->phy_page_addr = pages_per_blk; + if ((mtd->writesize < nandrsv_info->size) && (aml_chip->aml_nandenv_info->valid == 1)) i = (nandrsv_info->size + mtd->writesize - 1) / mtd->writesize; @@ -612,7 +623,6 @@ RE_SEARCH: nandrsv_info->valid_node->phy_page_addr += i; if ((nandrsv_info->valid_node->phy_page_addr+i) > pages_per_blk) { if ((nandrsv_info->valid_node->phy_page_addr - i) == pages_per_blk) { - nandrsv_info->valid_node->status = 0; addr = nandrsv_info->valid_node->phy_blk_addr; addr *= mtd->erasesize; memset(&erase_info, @@ -623,7 +633,6 @@ if ((nandrsv_info->valid_node->phy_page_addr+i) > pages_per_blk) { _aml_rsv_disprotect(); error = mtd->_erase(mtd, &erase_info); _aml_rsv_protect(); - nandrsv_info->valid_node->status = 1; nandrsv_info->valid_node->ec++; pr_info("---erase bad env block:%llx\n", addr); } @@ -687,7 +696,6 @@ if ((nandrsv_info->valid_node->phy_page_addr+i) > pages_per_blk) { erase_info.mtd = mtd; erase_info.addr = addr; erase_info.len = mtd->erasesize; - nandrsv_info->valid_node->status = 0; _aml_rsv_disprotect(); error = mtd->_erase(mtd, &erase_info); _aml_rsv_protect(); @@ -697,7 +705,6 @@ if ((nandrsv_info->valid_node->phy_page_addr+i) > pages_per_blk) { return error; } nandrsv_info->valid_node->ec++; - nandrsv_info->valid_node->status = 1; } if (aml_nand_write_rsv(mtd, nandrsv_info, addr, (u_char *) buf)) { @@ -705,6 +712,8 @@ if ((nandrsv_info->valid_node->phy_page_addr+i) > pages_per_blk) { return 1; } + /* clear status when write successfully*/ + nandrsv_info->valid_node->status = 0; return error; } @@ -815,7 +824,6 @@ int aml_nand_rsv_info_init(struct mtd_info *mtd) return -ENOMEM; aml_chip->aml_nandbbt_info->valid_node->phy_blk_addr = -1; - aml_chip->aml_nandbbt_info->valid_node->status = 1; aml_chip->aml_nandbbt_info->start_block = bbt_start_block; aml_chip->aml_nandbbt_info->end_block = aml_chip->aml_nandbbt_info->start_block + 4; @@ -844,7 +852,6 @@ int aml_nand_rsv_info_init(struct mtd_info *mtd) return -ENOMEM; aml_chip->aml_nandenv_info->valid_node->phy_blk_addr = -1; - aml_chip->aml_nandenv_info->valid_node->status = 1; aml_chip->aml_nandenv_info->start_block = aml_chip->aml_nandbbt_info->end_block; aml_chip->aml_nandenv_info->end_block = @@ -865,7 +872,6 @@ int aml_nand_rsv_info_init(struct mtd_info *mtd) return -ENOMEM; aml_chip->aml_nandkey_info->valid_node->phy_blk_addr = -1; - aml_chip->aml_nandkey_info->valid_node->status = 1; aml_chip->aml_nandkey_info->start_block = aml_chip->aml_nandenv_info->end_block; aml_chip->aml_nandkey_info->end_block = @@ -886,7 +892,6 @@ int aml_nand_rsv_info_init(struct mtd_info *mtd) return -ENOMEM; aml_chip->aml_nanddtb_info->valid_node->phy_blk_addr = -1; - aml_chip->aml_nanddtb_info->valid_node->status = 1; aml_chip->aml_nanddtb_info->start_block = aml_chip->aml_nandkey_info->end_block; aml_chip->aml_nanddtb_info->end_block = @@ -979,6 +984,7 @@ RE_RSV_INFO: /* pr_info("%s %d\n", __func__, __LINE__); */ nandrsv_info->init = 1; + nandrsv_info->valid_node->status = 0; if (!memcmp(oobinfo->name, nandrsv_info->name, 4)) { /* pr_info("%s %d\n", __func__, __LINE__); */ nandrsv_info->valid = 1; -- 2.7.4