static int __init ns_init_module()

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;
}