in nand/raw/nandsim.c [2256:2415]
static int __init ns_init_module(void)
{
struct list_head *pos, *n;
struct nand_chip *chip;
struct nandsim *ns;
int ret;
if (bus_width != 8 && bus_width != 16) {
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
return -EINVAL;
}
ns = kzalloc(sizeof(struct nandsim), GFP_KERNEL);
if (!ns) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
}
chip = &ns->chip;
nsmtd = nand_to_mtd(chip);
nand_set_controller_data(chip, (void *)ns);
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
/* and 'badblocks' parameters to work */
chip->options |= NAND_SKIP_BBTSCAN;
switch (bbt) {
case 2:
chip->bbt_options |= NAND_BBT_NO_OOB;
fallthrough;
case 1:
chip->bbt_options |= NAND_BBT_USE_FLASH;
fallthrough;
case 0:
break;
default:
NS_ERR("bbt has to be 0..2\n");
ret = -EINVAL;
goto free_ns_struct;
}
/*
* Perform minimum nandsim structure initialization to handle
* the initial ID read command correctly
*/
if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
ns->geom.idbytes = 8;
else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
ns->geom.idbytes = 6;
else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
ns->geom.idbytes = 4;
else
ns->geom.idbytes = 2;
ns->regs.status = NS_STATUS_OK(ns);
ns->nxstate = STATE_UNKNOWN;
ns->options |= OPT_PAGE512; /* temporary value */
memcpy(ns->ids, id_bytes, sizeof(ns->ids));
if (bus_width == 16) {
ns->busw = 16;
chip->options |= NAND_BUSWIDTH_16;
}
nsmtd->owner = THIS_MODULE;
ret = ns_parse_weakblocks();
if (ret)
goto free_ns_struct;
ret = ns_parse_weakpages();
if (ret)
goto free_wb_list;
ret = ns_parse_gravepages();
if (ret)
goto free_wp_list;
nand_controller_init(&ns->base);
ns->base.ops = &ns_controller_ops;
chip->controller = &ns->base;
ret = nand_scan(chip, 1);
if (ret) {
NS_ERR("Could not scan NAND Simulator device\n");
goto free_gp_list;
}
if (overridesize) {
uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
struct nand_memory_organization *memorg;
u64 targetsize;
memorg = nanddev_get_memorg(&chip->base);
if (new_size >> overridesize != nsmtd->erasesize) {
NS_ERR("overridesize is too big\n");
ret = -EINVAL;
goto cleanup_nand;
}
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
nsmtd->size = new_size;
memorg->eraseblocks_per_lun = 1 << overridesize;
targetsize = nanddev_target_size(&chip->base);
chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
chip->pagemask = (targetsize >> chip->page_shift) - 1;
}
ret = ns_setup_wear_reporting(nsmtd);
if (ret)
goto cleanup_nand;
ret = ns_init(nsmtd);
if (ret)
goto free_ebw;
ret = nand_create_bbt(chip);
if (ret)
goto free_ns_object;
ret = ns_parse_badblocks(ns, nsmtd);
if (ret)
goto free_ns_object;
/* Register NAND partitions */
ret = mtd_device_register(nsmtd, &ns->partitions[0], ns->nbparts);
if (ret)
goto free_ns_object;
ret = ns_debugfs_create(ns);
if (ret)
goto unregister_mtd;
return 0;
unregister_mtd:
WARN_ON(mtd_device_unregister(nsmtd));
free_ns_object:
ns_free(ns);
free_ebw:
kfree(erase_block_wear);
cleanup_nand:
nand_cleanup(chip);
free_gp_list:
list_for_each_safe(pos, n, &grave_pages) {
list_del(pos);
kfree(list_entry(pos, struct grave_page, list));
}
free_wp_list:
list_for_each_safe(pos, n, &weak_pages) {
list_del(pos);
kfree(list_entry(pos, struct weak_page, list));
}
free_wb_list:
list_for_each_safe(pos, n, &weak_blocks) {
list_del(pos);
kfree(list_entry(pos, struct weak_block, list));
}
free_ns_struct:
kfree(ns);
return ret;
}