linux挂载squash的时候默认不检查坏块,当遇到坏块的时候会挂载失败,确认linux内核版本 LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)
以下为novatek 98560使用的内核上的修改,按添加说明添加即可
1、/drivers/mtd/mtdpart.c文件中添加函数
#define CONFIG_SKIP_SQUASHFS_BAD_BLOCK
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
#include <linux/mtd/nand.h>
#include <linux/mtd/rawnand.h>
#define MAX_PARTITION_MAPPING 4
struct part_map{
struct mtd_info *part_mtd; /* Mapping partition mtd */
unsigned *map_table; /* Mapping from logic block to phys block */
unsigned nBlock; /* Logic block number */
};
static struct part_map *part_mapping[MAX_PARTITION_MAPPING];
static int part_mapping_count = -1;
static loff_t ajust_offset(struct mtd_info *mtd, loff_t from)
{
struct mtd_part *part = mtd_to_part(mtd);
struct nand_chip *this = part->parent->priv;
unsigned logic_b, phys_b;
unsigned index;
if(part_mapping_count <= 0)
return from;
for( index = 0; index < MAX_PARTITION_MAPPING; index++ )
{
if(!part_mapping[index] || part_mapping[index]->part_mtd != mtd)
continue;
/* remap from logic block to physical block */
logic_b = from >> this->bbt_erase_shift;
if ( logic_b < part_mapping[index]->nBlock )
{
phys_b = part_mapping[index]->map_table[logic_b];
from = phys_b << this->bbt_erase_shift | (from&(mtd->erasesize-1));
break;
}
}
return from;
}
static int part_create_partition_mapping ( struct mtd_info *part_mtd )
{
struct mtd_part *part = mtd_to_part(part_mtd);
struct nand_chip *this = part->parent->priv;
struct part_map *map_part;
int index;
unsigned offset;
int logical_b, phys_b;
if (!part_mtd || !this || part_mtd->type == MTD_NORFLASH)
{
printk("null mtd or it is no nand chip!");
return -1;
}
if ( part_mapping_count < 0 )
{
/* Init the part mapping table when this function called first time */
memset(part_mapping, 0, sizeof(struct part_map *)*MAX_PARTITION_MAPPING);
part_mapping_count = 0;
}
for ( index = 0; index < MAX_PARTITION_MAPPING; index++ )
{
if ( part_mapping[index] == NULL )
break;
}
if ( index >= MAX_PARTITION_MAPPING )
{
printk("partition mapping is full!");
return -1;
}
map_part = kmalloc(sizeof(struct part_map), GFP_KERNEL);
if ( !map_part )
{
printk ("memory allocation error while creating partitions mapping for %s/n",
part_mtd->name);
return -1;
}
map_part->map_table = kmalloc(sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift),
GFP_KERNEL);
if ( !map_part->map_table )
{
printk ("memory allocation error while creating partitions mapping for %s/n", part_mtd->name);
kfree(map_part);
return -1;
}
memset(map_part->map_table, 0xFF, sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift));
/* Create partition mapping table */
logical_b = 0;
for ( offset=0; offset<part_mtd->size; offset+=part_mtd->erasesize )
{
if ( part_mtd->_block_isbad &&
part_mtd->_block_isbad(part_mtd, offset) )
continue;
phys_b = offset >> this->bbt_erase_shift;
map_part->map_table[logical_b] = phys_b;
//printk("part[%s]: logic[%u]=phys[%u]\n",part_mtd->name, logical_b, phys_b);
logical_b++;
}
map_part->nBlock = logical_b;
map_part->part_mtd = part_mtd;
part_mapping[index] = map_part;
part_mapping_count++;
return 0;
}
static void part_del_partition_mapping( struct mtd_info *part_mtd )
{
int index;
struct part_map *map_part;
if (part_mapping_count <= 0)
return;
for (index = 0; index < MAX_PARTITION_MAPPING; index++ )
{
map_part = part_mapping[index];
if(!map_part || map_part->part_mtd != part_mtd)
continue;
kfree(map_part->map_table);
kfree(map_part);
part_mapping[index] = NULL;
part_mapping_count--;
}
}
static int part_is_squashfs( struct mtd_info *part_mtd )
{
struct mtd_part *part = mtd_to_part(part_mtd);
struct nand_chip *this = part->parent->priv;
u_char buf[16];
size_t retlen;
unsigned offset;
unsigned check_size = part_mtd->erasesize*2;
if (!part_mtd || !this || part_mtd->type == MTD_NORFLASH)
{
//printk("null mtd or it is no nand chip!");
return 0;
}
for (offset=0; offset<check_size; offset+=part_mtd->erasesize)
{
if (part_mtd->_block_isbad &&
part_mtd->_block_isbad(part_mtd, offset))
{
// 防止要检查的开始几个块是坏块
check_size += part_mtd->erasesize;
continue;
}
if(part_mtd->_read)
{
part_mtd->_read(part_mtd, offset, 16, &retlen, buf);
if(!memcmp(buf, "hsqs", 4))
{
// printk("%s:%d partition is squashfs,%s\n", __func__, __LINE__,buf);
return 1;
}
}
}
return 0;
}
#endif
下面的函数添加相关代码
static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
struct mtd_ecc_stats stats;
int res;
//添加下面3行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
from = ajust_offset(mtd, from);
#endif
stats = part->parent->ecc_stats;
res = part->parent->_read(part->parent, from + part->offset, len,
retlen, buf);
if (unlikely(mtd_is_eccerr(res)))
mtd->ecc_stats.failed +=
part->parent->ecc_stats.failed - stats.failed;
else
mtd->ecc_stats.corrected +=
part->parent->ecc_stats.corrected - stats.corrected;
return res;
}
static int part_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
struct mtd_part *part = mtd_to_part(mtd);
struct mtd_ecc_stats stats;
int res;
//添加下面3行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
from = ajust_offset(mtd, from);
#endif
stats = part->parent->ecc_stats;
res = part->parent->_read_oob(part->parent, from + part->offset, ops);
if (unlikely(mtd_is_eccerr(res)))
mtd->ecc_stats.failed +=
part->parent->ecc_stats.failed - stats.failed;
else
mtd->ecc_stats.corrected +=
part->parent->ecc_stats.corrected - stats.corrected;
return res;
}
int mtd_add_partition(struct mtd_info *parent, const char *name,
long long offset, long long length)
{
struct mtd_partition part;
struct mtd_part *new;
int ret = 0;
/* the direct offset is expected */
if (offset == MTDPART_OFS_APPEND ||
offset == MTDPART_OFS_NXTBLK)
return -EINVAL;
if (length == MTDPART_SIZ_FULL)
length = parent->size - offset;
if (length <= 0)
return -EINVAL;
memset(&part, 0, sizeof(part));
part.name = name;
part.size = length;
part.offset = offset;
new = allocate_partition(parent, &part, -1, offset);
if (IS_ERR(new))
return PTR_ERR(new);
mutex_lock(&mtd_partitions_mutex);
list_add(&new->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
ret = add_mtd_device(&new->mtd);
if (ret)
goto err_remove_part;
mtd_add_partition_attrs(new);
//添加下面4行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
if(part_is_squashfs(&new->mtd))
part_create_partition_mapping(&new->mtd);
#endif
return 0;
err_remove_part:
mutex_lock(&mtd_partitions_mutex);
list_del(&new->list);
mutex_unlock(&mtd_partitions_mutex);
free_partition(new);
return ret;
}
int del_mtd_partitions(struct mtd_info *mtd)
{
struct mtd_part *slave, *next;
int ret, err = 0;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if (slave->parent == mtd) {
//添加下面3行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
part_del_partition_mapping(&slave->mtd);
#endif
ret = __mtd_del_partition(slave);
if (ret < 0)
err = ret;
}
mutex_unlock(&mtd_partitions_mutex);
return err;
}
int mtd_del_partition(struct mtd_info *mtd, int partno)
{
struct mtd_part *slave, *next;
int ret = -EINVAL;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if ((slave->parent == mtd) &&
(slave->mtd.index == partno)) {
//添加下面3行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
part_del_partition_mapping(&slave->mtd);
#endif
ret = __mtd_del_partition(slave);
break;
}
mutex_unlock(&mtd_partitions_mutex);
return ret;
}
int add_mtd_partitions(struct mtd_info *master,
const struct mtd_partition *parts,
int nbparts)
{
struct mtd_part *slave;
uint64_t cur_offset = 0;
int i, ret;
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
for (i = 0; i < nbparts; i++) {
slave = allocate_partition(master, parts + i, i, cur_offset);
if (IS_ERR(slave)) {
ret = PTR_ERR(slave);
goto err_del_partitions;
}
mutex_lock(&mtd_partitions_mutex);
list_add(&slave->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
ret = add_mtd_device(&slave->mtd);
if (ret) {
mutex_lock(&mtd_partitions_mutex);
list_del(&slave->list);
mutex_unlock(&mtd_partitions_mutex);
free_partition(slave);
goto err_del_partitions;
}
mtd_add_partition_attrs(slave);
/* Look for subpartitions */
parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
//添加下面4行
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
if(part_is_squashfs(&slave->mtd))
part_create_partition_mapping(&slave->mtd);
#endif
cur_offset = slave->offset + slave->mtd.size;
}
return 0;
err_del_partitions:
del_mtd_partitions(master);
return ret;
}
2、/drivers/mtd/nand/raw/nand_base.c修改如下
确认下面函数是否非定义,未定义就要定义下面函数
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf)
{
struct mtd_oob_ops ops;
int ret;
nand_get_device(mtd, FL_READING);
memset(&ops, 0, sizeof(ops));
ops.len = len;
ops.datbuf = buf;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
nand_release_device(mtd);
return ret;
}
//找到static int nand_scan_tail(struct mtd_info *mtd)函数
/* Fill in remaining MTD driver data */
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
MTD_CAP_NANDFLASH;
mtd->_erase = nand_erase;
mtd->_point = NULL;
mtd->_unpoint = NULL;
mtd->_panic_write = panic_nand_write;
mtd->_read = nand_read;//如果没有赋值就赋值
mtd->_read_oob = nand_read_oob;
mtd->_write_oob = nand_write_oob;
mtd->_sync = nand_sync;
mtd->_lock = NULL;
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;//如果没有赋值就赋值,
mtd->_block_markbad = nand_block_markbad;
mtd->_max_bad_blocks = nand_max_bad_blocks;
mtd->writebufsize = mtd->writesize;
//mtd->_block_isbad和mtd->_read = nand_read这两个函数在检查的时候要用,确认这里赋值
3、修改/drivers/mtd/spiflash/spinand.c文件如下
static int spinand_probe(struct platform_device *pdev)
{
struct drv_nand_dev_info *info;
struct mtd_part_parser_data ppdata;
struct platform_nand_data *pplatdata;
struct nand_chip *this;
struct mtd_info *mtd;
struct resource *res;
int ret = 0;
u8 chip_id;
//添加下面2行
static const char *part_probes[] = { "cmdlinepart", NULL, };
int err = 0;
info = devm_kzalloc(&pdev->dev, sizeof(struct drv_nand_dev_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->pdev = pdev;
info->flash_info = kmalloc(sizeof(struct nvt_nand_flash), GFP_KERNEL);
if (!info->flash_info) {
dev_err(&pdev->dev, "failed to allocate nvt_nand_flash\n");
return -ENOMEM;
}
pplatdata = NULL;
if (pdev->dev.platform_data != NULL)
{
pplatdata = pdev->dev.platform_data;
}
platform_set_drvdata(pdev, info);
this = &info->nand_chip;
mtd = nand_to_mtd(this);
//添加下面2行
/* Initialize structures */
mtd->priv = this;
/* Get mtd device resource of base address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get resource\n");
goto fail_free_mtd;
}
info->mmio_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->mmio_base)) {
PTR_ERR(info->mmio_base);
goto fail_free_mtd;
}
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
dev_err(&pdev->dev, "no IRQ resource defined\n");
ret = -ENXIO;
goto fail_free_mtd;
}
ret = drv_nand_init_buff(info);
if (ret) {
dev_err(&pdev->dev, "failed to allocate buffer\n");
goto fail_free_buf;
}
ret = request_irq(info->irq, spinand_irq, IRQF_SHARED, pdev->name, info);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto fail_free_buf;
}
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&info->flash_freq);
mutex_init(&info->lock);
init_completion(&info->cmd_complete);
mutex_lock(&info->lock);
drv_nand_reset(info, pdev);
nand_phy_config(info);
nand_dll_reset(info);
mutex_unlock(&info->lock);
/*Delay 1ms for spinand characteristic*/
mdelay(1);
ret = drv_nand_identify(info);
if (ret) {
dev_err(&pdev->dev, "failed to identify flash\n");
ret = -ENODEV;
goto fail_free_irq;
}
spinand_init_mtd(info);
nand_set_flash_node(&info->nand_chip, pdev->dev.of_node);
#ifdef CONFIG_OF
of_property_read_string_index(pdev->dev.of_node, "nvt-devname", 0, &mtd->name);
#else
mtd->name = dev_name(&pdev->dev);
#endif
mtd->owner = THIS_MODULE;
mtd->oobsize = 64;
chip_id = info->flash_info->chip_id & 0xFF;
if (info->use_ecc == NANDCTRL_SPIFLASH_USE_INTERNAL_RS_ECC) {
info->nand_chip.ecc.strength = 4;
mtd->bitflip_threshold = 2;
} else {
if (chip_id == MFG_ID_WINBOND) {
if (info->flash_info->chip_id == WINBOND_W25N02KV) {
info->nand_chip.ecc.strength = 8;
mtd->bitflip_threshold = 6;
} else
mtd->bitflip_threshold = 1;
} else if (chip_id == MFG_ID_MXIC) {
info->nand_chip.ecc.strength = 4;
mtd->bitflip_threshold = 3;
} else if (chip_id == MFG_ID_MICRON) {
if (((info->flash_info->chip_id) & 0xFFFF) == MICRON_MT29F1G01AA) {
mtd->bitflip_threshold = 1;
} else {
info->nand_chip.ecc.strength = 8;
mtd->bitflip_threshold = 6;
}
} else if (chip_id == MFG_ID_TOSHIBA) {
if (info->flash_info->page_size == 4096) {
info->nand_chip.ecc.strength = 8;
mtd->bitflip_threshold = 6;
} else {
info->nand_chip.ecc.strength = 8;
mtd->bitflip_threshold = 3;
}
} else if (chip_id == MFG_ID_XTX) {
info->nand_chip.ecc.strength = 8;
mtd->bitflip_threshold = 6;
} else {
mtd->bitflip_threshold = DIV_ROUND_UP(info->nand_chip.ecc.strength * 3, 4);
}
}
#ifndef CONFIG_FLASH_ONLY_DUAL
if ((info->flash_info->chip_id & 0xFFFF) != TOSHIBA_TC58CVG && (info->flash_info->chip_id & 0xFFFF) != TOSHIBA_TC58CVG3)
info->flash_info->spi_nand_status.quad_program = TRUE;
#endif
ret = nand_scan_with_ids(mtd, 1, spinand_flash_ids);
if (ret) {
dev_err(&pdev->dev, "Identify nand fail\n");
goto fail_free_irq;
}
dev_info(&pdev->dev, "%d-bit mode @ %d Hz\n",
info->flash_info->spi_nand_status.quad_program ? 4 : 1,
info->flash_freq);
//添加下面4行
err = parse_mtd_partitions(mtd, part_probes, 0);
if (err) {
dev_err(&pdev->dev, "parse_mtd_partitions failed\n");
}
ret = nvt_nand_proc_init();
if (ret) {
dev_err(&pdev->dev, "create nand static proc failed\n");
}
//ppdata.of_node = pdev->dev.of_node;
mtd->dev.of_node = pdev->dev.of_node;;
if (pplatdata == NULL)
return mtd_device_register(mtd, NULL, 0);
else
return mtd_device_parse_register(mtd, NULL, &ppdata,
pplatdata->chip.partitions,
pplatdata->chip.nr_partitions);
fail_free_irq:
free_irq(info->irq, info);
fail_free_buf:
kfree(info->data_buff);
fail_free_mtd:
kfree(mtd);
return ret;
}