static int __init ns_init()

in nand/raw/nandsim.c [637:781]


static int __init ns_init(struct mtd_info *mtd)
{
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct nandsim   *ns   = nand_get_controller_data(chip);
	int i, ret = 0;
	uint64_t remains;
	uint64_t next_offset;

	if (NS_IS_INITIALIZED(ns)) {
		NS_ERR("init_nandsim: nandsim is already initialized\n");
		return -EIO;
	}

	/* Initialize the NAND flash parameters */
	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
	ns->geom.totsz    = mtd->size;
	ns->geom.pgsz     = mtd->writesize;
	ns->geom.oobsz    = mtd->oobsize;
	ns->geom.secsz    = mtd->erasesize;
	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
	ns->geom.pgshift  = chip->page_shift;
	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
	ns->options = 0;

	if (ns->geom.pgsz == 512) {
		ns->options |= OPT_PAGE512;
		if (ns->busw == 8)
			ns->options |= OPT_PAGE512_8BIT;
	} else if (ns->geom.pgsz == 2048) {
		ns->options |= OPT_PAGE2048;
	} else if (ns->geom.pgsz == 4096) {
		ns->options |= OPT_PAGE4096;
	} else {
		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
		return -EIO;
	}

	if (ns->options & OPT_SMALLPAGE) {
		if (ns->geom.totsz <= (32 << 20)) {
			ns->geom.pgaddrbytes  = 3;
			ns->geom.secaddrbytes = 2;
		} else {
			ns->geom.pgaddrbytes  = 4;
			ns->geom.secaddrbytes = 3;
		}
	} else {
		if (ns->geom.totsz <= (128 << 20)) {
			ns->geom.pgaddrbytes  = 4;
			ns->geom.secaddrbytes = 2;
		} else {
			ns->geom.pgaddrbytes  = 5;
			ns->geom.secaddrbytes = 3;
		}
	}

	/* Fill the partition_info structure */
	if (parts_num > ARRAY_SIZE(ns->partitions)) {
		NS_ERR("too many partitions.\n");
		return -EINVAL;
	}
	remains = ns->geom.totsz;
	next_offset = 0;
	for (i = 0; i < parts_num; ++i) {
		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;

		if (!part_sz || part_sz > remains) {
			NS_ERR("bad partition size.\n");
			return -EINVAL;
		}
		ns->partitions[i].name = ns_get_partition_name(i);
		if (!ns->partitions[i].name) {
			NS_ERR("unable to allocate memory.\n");
			return -ENOMEM;
		}
		ns->partitions[i].offset = next_offset;
		ns->partitions[i].size   = part_sz;
		next_offset += ns->partitions[i].size;
		remains -= ns->partitions[i].size;
	}
	ns->nbparts = parts_num;
	if (remains) {
		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
			NS_ERR("too many partitions.\n");
			ret = -EINVAL;
			goto free_partition_names;
		}
		ns->partitions[i].name = ns_get_partition_name(i);
		if (!ns->partitions[i].name) {
			NS_ERR("unable to allocate memory.\n");
			ret = -ENOMEM;
			goto free_partition_names;
		}
		ns->partitions[i].offset = next_offset;
		ns->partitions[i].size   = remains;
		ns->nbparts += 1;
	}

	if (ns->busw == 16)
		NS_WARN("16-bit flashes support wasn't tested\n");

	printk("flash size: %llu MiB\n",
			(unsigned long long)ns->geom.totsz >> 20);
	printk("page size: %u bytes\n",         ns->geom.pgsz);
	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
	printk("pages number: %u\n",            ns->geom.pgnum);
	printk("pages per sector: %u\n",        ns->geom.pgsec);
	printk("bus width: %u\n",               ns->busw);
	printk("bits in sector size: %u\n",     ns->geom.secshift);
	printk("bits in page size: %u\n",       ns->geom.pgshift);
	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
	printk("flash size with OOB: %llu KiB\n",
			(unsigned long long)ns->geom.totszoob >> 10);
	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
	printk("options: %#x\n",                ns->options);

	ret = ns_alloc_device(ns);
	if (ret)
		goto free_partition_names;

	/* Allocate / initialize the internal buffer */
	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
	if (!ns->buf.byte) {
		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
			ns->geom.pgszoob);
		ret = -ENOMEM;
		goto free_device;
	}
	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);

	return 0;

free_device:
	ns_free_device(ns);
free_partition_names:
	for (i = 0; i < ARRAY_SIZE(ns->partitions); ++i)
		kfree(ns->partitions[i].name);

	return ret;
}