nand ubi -4 kernel和mtd
tiny6410 linux2.6.38
1.nand驱动
nand是作为平台设备,在板子文件mach-mini6410.c调用,系统启动时自动加载进内核
搜索内核中的s3c6410-nand字符串,在driver/mtd/nand/s3c_nand.c中发现有一处匹配。可以断定这里就是nand的平台驱动
从make menuconfig中也可以得知,如下
Device Drivers ---> <*> Memory Technology Device (MTD) support --->[*] MTD partitioning support
<*> Direct char device access to MTD devices
<*> Caching block device access to MTD devices
<*> NAND Device Support ---> <*> NAND Flash support for S3C SoC
最后一项对应的就是s3c_nand.c,为6410板子配置的nandflash的驱动。下面是平台驱动
s3c_nand.c
从probe看起,搜索“见下面“
此函数主要对nand_chip结构体chip进行填充。nand_chip描述nand芯片。不同型号的nand,其主要的不同就是nand_chip。
s3c_nand.c
nand_scan会调用nand_scan_tail函数扫描nand,并使用nand_base.c中预定义的一些读写nand的函数来初始化mtd_info结构体的函数指针。
这个mtd_info会在稍后add_mtd_partitions时给各个分区的mtd_info赋值。
nand_base.c
add_mtd_partitions函数会循环调用nr_partitions次allocate_partition函数来给flash分为nr_partitions个区
每个分区使用一个mtd_part描述,而mtd_part中都有一个mtd_info结构体用于具体描述这个分区。此mtd_info中的结构体的函数指针很多都执行master的函数。而master就是上面执行nand_scan_tail时,被初始化的一个mtd_info结构体。
mtdpart.c
有个疑问
nand_chip的ecc结构体有很多读写函数,ecc结构体的函数指针在nand_scan_tail中被赋值,比如
/* Use standard hwecc read page function ? */
if (!chip->ecc.read_page)
chip->ecc.read_page = nand_read_page_hwecc;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_hwecc;
if (!chip->ecc.read_page_raw)
chip->ecc.read_page_raw = nand_read_page_raw;
if (!chip->ecc.write_page_raw)
chip->ecc.write_page_raw = nand_write_page_raw;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_std;
而每个分区mtd_part结构体的mtd_info结构体也有很多读写函数,函数指针在allocate_partition中被赋值,比如
slave->mtd.read = part_read;
slave->mtd.write = part_write;
if (master->panic_write)
slave->mtd.panic_write = part_panic_write;
if (master->point && master->unpoint) {
slave->mtd.point = part_point;
slave->mtd.unpoint = part_unpoint;
}
if (master->get_unmapped_area)
slave->mtd.get_unmapped_area = part_get_unmapped_area;
if (master->read_oob)
slave->mtd.read_oob = part_read_oob;
if (master->write_oob)
slave->mtd.write_oob = part_write_oob;
if (master->read_user_prot_reg)
slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
if (master->read_fact_prot_reg)
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
if (master->write_user_prot_reg)
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
if (master->lock_user_prot_reg)
slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
if (master->get_user_prot_info)
slave->mtd.get_user_prot_info = part_get_user_prot_info;
if (master->get_fact_prot_info)
slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
if (master->sync)
slave->mtd.sync = part_sync;
if (!partno && !master->dev.class && master->suspend && master->resume) {
slave->mtd.suspend = part_suspend;
slave->mtd.resume = part_resume;
}
if (master->writev)
slave->mtd.writev = part_writev;
if (master->lock)
slave->mtd.lock = part_lock;
if (master->unlock)
slave->mtd.unlock = part_unlock;
if (master->is_locked)
slave->mtd.is_locked = part_is_locked;
if (master->block_isbad)
slave->mtd.block_isbad = part_block_isbad;
if (master->block_markbad)
slave->mtd.block_markbad = part_block_markbad;
slave->mtd.erase = part_erase;
slave->master = master;
slave->offset = part->offset;
这两个结构体的读写函数有啥不同呢?待续。。。。。
2.内核加载ubi
mtdchar.c
mtdblock.c
加载mtd分区上的文件系统后,执行文件系统根目录的linuxrc(因为 setenv bootargs console=ttySAC0 noinitrd root=/dev/mtdblock3 init=/linuxrc)和init
见内核源码init/main.c init_post()
http://qiuye.iteye.com/blog/543595
1.nand驱动
nand是作为平台设备,在板子文件mach-mini6410.c调用,系统启动时自动加载进内核
static struct platform_device *mini6410_devices[] __initdata = { ... &s3c_device_nand, ... } static void __init mini6410_machine_init(void) { ... #ifdef CONFIG_MTD_NAND_S3C s3c_device_nand.name = "s3c6410-nand";//改s3c2410-nand叫s3c6410-nand #endif ... platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices)); ... } static struct resource s3c_nand_resource[] = { [0] = { .start = S3C_PA_NAND, .end = S3C_PA_NAND + SZ_1M, .flags = IORESOURCE_MEM, } }; struct platform_device s3c_device_nand = { .name = "s3c2410-nand", .id = -1, .num_resources = ARRAY_SIZE(s3c_nand_resource), .resource = s3c_nand_resource, };
搜索内核中的s3c6410-nand字符串,在driver/mtd/nand/s3c_nand.c中发现有一处匹配。可以断定这里就是nand的平台驱动
从make menuconfig中也可以得知,如下
Device Drivers ---> <*> Memory Technology Device (MTD) support --->[*] MTD partitioning support
<*> Direct char device access to MTD devices
<*> Caching block device access to MTD devices
<*> NAND Device Support ---> <*> NAND Flash support for S3C SoC
最后一项对应的就是s3c_nand.c,为6410板子配置的nandflash的驱动。下面是平台驱动
s3c_nand.c
static struct platform_driver s3c6410_nand_driver = { .probe = s3c6410_nand_probe, .remove = s3c_nand_remove, .suspend = s3c_nand_suspend, .resume = s3c_nand_resume, .driver = { .name = "s3c6410-nand", .owner = THIS_MODULE, }, };
从probe看起,搜索“见下面“
此函数主要对nand_chip结构体chip进行填充。nand_chip描述nand芯片。不同型号的nand,其主要的不同就是nand_chip。
s3c_nand.c
static int s3c6410_nand_probe(struct platform_device *dev) { return s3c_nand_probe(dev, TYPE_S3C6410); } /* s3c_nand_probe * * called by device layer when it finds a device matching * one our driver can handled. This code checks to see if * it can allocate all necessary resources then calls the * nand layer to look for devices */ static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type) { struct s3c2410_platform_nand *plat = pdev->dev.platform_data; struct s3c2410_nand_set *sets; struct nand_chip *nand; struct resource *res; struct mtd_partition *partitions; int nr_partitions; int err = 0; int ret = 0; int nr_sets; int i, j, size; #if defined(CONFIG_MTD_NAND_S3C_HWECC)//硬件ecc struct nand_flash_dev *type = NULL; u_char tmp; #endif /* get the clock source and enable it */ s3c_nand.clk = clk_get(&pdev->dev, "nand"); if (IS_ERR(s3c_nand.clk)) { dev_err(&pdev->dev, "failed to get clock"); err = -ENOENT; goto exit_error; } clk_enable(s3c_nand.clk); /* allocate and map the resource */ /* currently we assume we have the one resource */ res = pdev->resource; size = res->end - res->start + 1; s3c_nand.area = request_mem_region(res->start, size, pdev->name); if (s3c_nand.area == NULL) { dev_err(&pdev->dev, "cannot reserve register region\n"); err = -ENOENT; goto exit_error; } s3c_nand.cpu_type = cpu_type; s3c_nand.device = &pdev->dev; s3c_nand.regs = ioremap(res->start, size); s3c_nand.platform = plat; if (s3c_nand.regs == NULL) { dev_err(&pdev->dev, "cannot reserve register region\n"); err = -EIO; goto exit_error; } sets = (plat != NULL) ? plat->sets : NULL; nr_sets = (plat != NULL) ? plat->nr_sets : 1; /* Using partition info from platform data for SLC nand */ partitions = sets->partitions;//使用mach-mini6410.c中定义的分区表给nand分区(SLC)。如果是MLC,后面会指定其他分区表。 nr_partitions = sets->nr_partitions; s3c_nand.mtd_count = nr_sets; /* allocate memory for MTD device structure and private data */ s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!s3c_mtd) { printk("Unable to allocate NAND MTD dev structure.\n"); return -ENOMEM; } /* Get pointer to private data */ nand = (struct nand_chip *) (&s3c_mtd[1]); /* Initialize structures */ memset((char *) s3c_mtd, 0, sizeof(struct mtd_info)); memset((char *) nand, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ s3c_mtd->priv = nand; for (i = 0; i < sets->nr_chips; i++) { nand->IO_ADDR_R = (char *)(s3c_nand.regs + S3C_NFDATA); nand->IO_ADDR_W = (char *)(s3c_nand.regs + S3C_NFDATA); nand->cmd_ctrl = s3c_nand_hwcontrol; nand->dev_ready = s3c_nand_device_ready; nand->scan_bbt = s3c_nand_scan_bbt; nand->options = 0; nand->badblockbits = 8; #ifdef CONFIG_MACH_MINI6410 s3c_nand_ext_finit(nand, s3c_nand.regs); #endif #if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG) nand->options |= NAND_CACHEPRG; #endif #if defined(CONFIG_MTD_NAND_S3C_HWECC) nand->ecc.mode = NAND_ECC_HW; nand->ecc.hwctl = s3c_nand_enable_hwecc; nand->ecc.calculate = s3c_nand_calculate_ecc; nand->ecc.correct = s3c_nand_correct_data; s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE); s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); s3c_nand_device_ready(0); tmp = readb(nand->IO_ADDR_R); /* Maf. ID */ tmp = readb(nand->IO_ADDR_R); /* Device ID */ for (j = 0; nand_flash_ids[j].name != NULL; j++) { if (tmp == nand_flash_ids[j].id) { type = &nand_flash_ids[j]; break; } } if (!type) { printk("Unknown NAND Device.\n"); goto exit_error; } nand->cellinfo = readb(nand->IO_ADDR_R); /* the 3rd byte */ tmp = readb(nand->IO_ADDR_R); /* the 4th byte */ if (!type->pagesize) { if (((nand->cellinfo >> 2) & 0x3) == 0) {//SLC nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512;////每次进行ecc的数据量(以子页位单位),bytes per ecc step.每页进行4次,共计2KB nand->ecc.bytes = 4;////每次ecc校验字节,ecc bytes per step。每页进行4次。共计16字节 if ((1024 << (tmp & 0x3)) > 512) {//对于1GB SLC而言 nand->ecc.read_page = s3c_nand_read_page_1bit;//SLC使用1位ecc nand->ecc.write_page = s3c_nand_write_page_1bit; nand->ecc.read_oob = s3c_nand_read_oob_1bit; nand->ecc.write_oob = s3c_nand_write_oob_1bit; nand->ecc.layout = &s3c_nand_oob_64;//1GB SLC的oob大小是64,见下面 } else { nand->ecc.layout = &s3c_nand_oob_16; } } else {//MLC nand_type = S3C_NAND_TYPE_MLC; nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */ if (type->id == 0xD5) { #if 0 type->chipsize = 2076; nand->chip_shift = 32; nand->pagemask = 0x7ffff; #endif nand->badblockbits = 4; } if ((2048 << (tmp & 3)) < 4096) { nand->ecc.read_page = s3c_nand_read_page_4bit;//MLC使用4位ecc nand->ecc.write_page = s3c_nand_write_page_4bit; nand->ecc.size = 512; nand->ecc.bytes = 8; /* really 7 bytes */ nand->ecc.layout = &s3c_nand_oob_mlc_64; } else { #ifdef CONFIG_MACH_MINI6410 partitions = mini6410_nand_part_mlc;//使用s3c_nand.c中定义的分区表给MLC分区 nr_partitions = ARRAY_SIZE(mini6410_nand_part_mlc); s3c_nand_mlc_probe(nand, s3c_nand.regs); #endif } } } else { nand_type = S3C_NAND_TYPE_SLC; nand->ecc.size = 512; nand->cellinfo = 0; nand->ecc.bytes = 4; nand->ecc.layout = &s3c_nand_oob_16; } printk("S3C NAND Driver is using hardware ECC.\n"); #else//软件ecc nand->ecc.mode = NAND_ECC_SOFT; printk("S3C NAND Driver is using software ECC.\n"); #endif if (nand_scan(s3c_mtd, 1)) {//扫描nand,并初始化s3c_mtd结构体里的一些函数指针 ret = -ENXIO; goto exit_error; } /* Register the partitions */ add_mtd_partitions(s3c_mtd, partitions, nr_partitions);//分区,见下面 } pr_debug("initialized ok\n"); return 0; exit_error: kfree(s3c_mtd); return ret; }s3c_nand.c
/* Nand flash oob definition for SLC 2k page size by jsgood */ static struct nand_ecclayout s3c_nand_oob_64 = { .eccbytes = 16, .eccpos = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}, .oobfree = { {.offset = 2, .length = 38}} }; //对于K9K8G0800B 1GB SLC,页大小是2KB, oob是64B,地址认为是0-63 ecc字节数16(所占地址从40-55,共计16字节) oob中空闲字节数38(所占地址从2-39) oob中剩余余的0-1和56-63另有用途
nand_scan会调用nand_scan_tail函数扫描nand,并使用nand_base.c中预定义的一些读写nand的函数来初始化mtd_info结构体的函数指针。
这个mtd_info会在稍后add_mtd_partitions时给各个分区的mtd_info赋值。
nand_base.c
/** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure * * This is the second phase of the normal nand_scan() function. It * fills out all the uninitialized function pointers with the defaults * and scans for a bad block table if appropriate. */ int nand_scan_tail(struct mtd_info *mtd) { int i; struct nand_chip *chip = mtd->priv; if (!(chip->options & NAND_OWN_BUFFERS)) chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); if (!chip->buffers) return -ENOMEM; /* Set the internal oob buffer location, just after the page data */ chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* * If no default placement scheme is given, select an appropriate one */ if (!chip->ecc.layout) { switch (mtd->oobsize) { case 8: chip->ecc.layout = &nand_oob_8; break; case 16: chip->ecc.layout = &nand_oob_16; break; case 64: chip->ecc.layout = &nand_oob_64; break; case 128: chip->ecc.layout = &nand_oob_128; break; default: printk(KERN_WARNING "No oob scheme defined for " "oobsize %d\n", mtd->oobsize); BUG(); } } if (!chip->write_page) chip->write_page = nand_write_page; /* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ switch (chip->ecc.mode) { case NAND_ECC_HW_OOB_FIRST: /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { printk(KERN_WARNING "No ECC functions supplied; " "Hardware ECC not possible\n"); BUG(); } if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: /* Use standard hwecc read page function ? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc; if (!chip->ecc.write_page) chip->ecc.write_page = nand_write_page_hwecc; if (!chip->ecc.read_page_raw) chip->ecc.read_page_raw = nand_read_page_raw; if (!chip->ecc.write_page_raw) chip->ecc.write_page_raw = nand_write_page_raw; if (!chip->ecc.read_oob) chip->ecc.read_oob = nand_read_oob_std; if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_std; case NAND_ECC_HW_SYNDROME: if ((!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) && (!chip->ecc.read_page || chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { printk(KERN_WARNING "No ECC functions supplied; " "Hardware ECC not possible\n"); BUG(); } /* Use standard syndrome read/write page function ? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.write_page) chip->ecc.write_page = nand_write_page_syndrome; if (!chip->ecc.read_page_raw) chip->ecc.read_page_raw = nand_read_page_raw_syndrome; if (!chip->ecc.write_page_raw) chip->ecc.write_page_raw = nand_write_page_raw_syndrome; if (!chip->ecc.read_oob) chip->ecc.read_oob = nand_read_oob_syndrome; if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_syndrome; if (mtd->writesize >= chip->ecc.size) break; printk(KERN_WARNING "%d byte HW ECC not possible on " "%d byte page size, fallback to SW ECC\n", chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: chip->ecc.calculate = nand_calculate_ecc; chip->ecc.correct = nand_correct_data; chip->ecc.read_page = nand_read_page_swecc; chip->ecc.read_subpage = nand_read_subpage; chip->ecc.write_page = nand_write_page_swecc; chip->ecc.read_page_raw = nand_read_page_raw; chip->ecc.write_page_raw = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; chip->ecc.write_oob = nand_write_oob_std; if (!chip->ecc.size) chip->ecc.size = 256; chip->ecc.bytes = 3; break; case NAND_ECC_NONE: printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " "This is not recommended !!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; chip->ecc.read_page_raw = nand_read_page_raw; chip->ecc.write_page_raw = nand_write_page_raw; chip->ecc.write_oob = nand_write_oob_std; chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; break; default: printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } /* * The number of bytes available for a client to place data into * the out of band area */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++) chip->ecc.layout->oobavail += chip->ecc.layout->oobfree[i].length; mtd->oobavail = chip->ecc.layout->oobavail; /* * Set the number of read / write steps for one page depending on ECC * mode */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { printk(KERN_WARNING "Invalid ecc parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; /* * Allow subpage writes up to ecc.steps. Not possible for MLC * FLASH. */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { switch (chip->ecc.steps) { case 2: mtd->subpage_sft = 1; break; case 4: case 8: case 16: mtd->subpage_sft = 2; break; } } chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Initialize state */ chip->state = FL_READY; /* De-select the device */ chip->select_chip(mtd, -1); /* Invalidate the pagebuffer reference */ chip->pagebuf = -1; /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : MTD_CAP_NANDFLASH; mtd->erase = nand_erase; mtd->point = NULL; mtd->unpoint = NULL; mtd->read = nand_read; mtd->write = nand_write; mtd->panic_write = panic_nand_write; 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->block_isbad = nand_block_isbad; mtd->block_markbad = nand_block_markbad; mtd->writebufsize = mtd->writesize; /* propagate ecc.layout to mtd_info */ mtd->ecclayout = chip->ecc.layout; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; /* Build bad block table */ return chip->scan_bbt(mtd); }
add_mtd_partitions函数会循环调用nr_partitions次allocate_partition函数来给flash分为nr_partitions个区
每个分区使用一个mtd_part描述,而mtd_part中都有一个mtd_info结构体用于具体描述这个分区。此mtd_info中的结构体的函数指针很多都执行master的函数。而master就是上面执行nand_scan_tail时,被初始化的一个mtd_info结构体。
mtdpart.c
static struct mtd_part *allocate_partition(struct mtd_info *master, const struct mtd_partition *part, int partno, uint64_t cur_offset) { struct mtd_part *slave; char *name; /* allocate the partition structure */ slave = kzalloc(sizeof(*slave), GFP_KERNEL); name = kstrdup(part->name, GFP_KERNEL); if (!name || !slave) { printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", master->name); kfree(name); kfree(slave); return ERR_PTR(-ENOMEM); } /* set up the MTD object for this partition */ slave->mtd.type = master->type; slave->mtd.flags = master->flags & ~part->mask_flags; slave->mtd.size = part->size; slave->mtd.writesize = master->writesize; slave->mtd.writebufsize = master->writebufsize; slave->mtd.oobsize = master->oobsize; slave->mtd.oobavail = master->oobavail; slave->mtd.subpage_sft = master->subpage_sft; slave->mtd.name = name; slave->mtd.owner = master->owner; slave->mtd.backing_dev_info = master->backing_dev_info; /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone * to have the same data be in two different partitions. */ slave->mtd.dev.parent = master->dev.parent; slave->mtd.read = part_read; slave->mtd.write = part_write; if (master->panic_write) slave->mtd.panic_write = part_panic_write; if (master->point && master->unpoint) { slave->mtd.point = part_point; slave->mtd.unpoint = part_unpoint; } if (master->get_unmapped_area) slave->mtd.get_unmapped_area = part_get_unmapped_area; if (master->read_oob) slave->mtd.read_oob = part_read_oob; if (master->write_oob) slave->mtd.write_oob = part_write_oob; if (master->read_user_prot_reg) slave->mtd.read_user_prot_reg = part_read_user_prot_reg; if (master->read_fact_prot_reg) slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; if (master->write_user_prot_reg) slave->mtd.write_user_prot_reg = part_write_user_prot_reg; if (master->lock_user_prot_reg) slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; if (master->get_user_prot_info) slave->mtd.get_user_prot_info = part_get_user_prot_info; if (master->get_fact_prot_info) slave->mtd.get_fact_prot_info = part_get_fact_prot_info; if (master->sync) slave->mtd.sync = part_sync; if (!partno && !master->dev.class && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } if (master->writev) slave->mtd.writev = part_writev; if (master->lock) slave->mtd.lock = part_lock; if (master->unlock) slave->mtd.unlock = part_unlock; if (master->is_locked) slave->mtd.is_locked = part_is_locked; if (master->block_isbad) slave->mtd.block_isbad = part_block_isbad; if (master->block_markbad) slave->mtd.block_markbad = part_block_markbad; slave->mtd.erase = part_erase; slave->master = master; slave->offset = part->offset; if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; if (slave->offset == MTDPART_OFS_NXTBLK) { slave->offset = cur_offset; if (mtd_mod_by_eb(cur_offset, master) != 0) { /* Round up to next erasesize */ slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; printk(KERN_NOTICE "Moving partition %d: " "0x%012llx -> 0x%012llx\n", partno, (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset, (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name); /* let's do some sanity checks */ if (slave->offset >= master->size) { /* let's register it anyway to preserve ordering */ slave->offset = 0; slave->mtd.size = 0; printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n", part->name); goto out_register; } if (slave->offset + slave->mtd.size > master->size) { slave->mtd.size = master->size - slave->offset; printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", part->name, master->name, (unsigned long long)slave->mtd.size); } if (master->numeraseregions > 1) { /* Deal with variable erase size stuff */ int i, max = master->numeraseregions; u64 end = slave->offset + slave->mtd.size; struct mtd_erase_region_info *regions = master->eraseregions; /* Find the first erase regions which is part of this * partition. */ for (i = 0; i < max && regions[i].offset <= slave->offset; i++) ; /* The loop searched for the region _behind_ the first one */ if (i > 0) i--; /* Pick biggest erasesize */ for (; i < max && regions[i].offset < end; i++) { if (slave->mtd.erasesize < regions[i].erasesize) { slave->mtd.erasesize = regions[i].erasesize; } } BUG_ON(slave->mtd.erasesize == 0); } else { /* Single erase size */ slave->mtd.erasesize = master->erasesize; } if ((slave->mtd.flags & MTD_WRITEABLE) && mtd_mod_by_eb(slave->offset, &slave->mtd)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ slave->mtd.flags &= ~MTD_WRITEABLE; printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", part->name); } if ((slave->mtd.flags & MTD_WRITEABLE) && mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { slave->mtd.flags &= ~MTD_WRITEABLE; printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", part->name); } slave->mtd.ecclayout = master->ecclayout; if (master->block_isbad) { uint64_t offs = 0; while (offs < slave->mtd.size) { if (master->block_isbad(master, offs + slave->offset)) slave->mtd.ecc_stats.badblocks++; offs += slave->mtd.erasesize; } } out_register: return slave; }
有个疑问
nand_chip的ecc结构体有很多读写函数,ecc结构体的函数指针在nand_scan_tail中被赋值,比如
/* Use standard hwecc read page function ? */
if (!chip->ecc.read_page)
chip->ecc.read_page = nand_read_page_hwecc;
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_hwecc;
if (!chip->ecc.read_page_raw)
chip->ecc.read_page_raw = nand_read_page_raw;
if (!chip->ecc.write_page_raw)
chip->ecc.write_page_raw = nand_write_page_raw;
if (!chip->ecc.read_oob)
chip->ecc.read_oob = nand_read_oob_std;
if (!chip->ecc.write_oob)
chip->ecc.write_oob = nand_write_oob_std;
而每个分区mtd_part结构体的mtd_info结构体也有很多读写函数,函数指针在allocate_partition中被赋值,比如
slave->mtd.read = part_read;
slave->mtd.write = part_write;
if (master->panic_write)
slave->mtd.panic_write = part_panic_write;
if (master->point && master->unpoint) {
slave->mtd.point = part_point;
slave->mtd.unpoint = part_unpoint;
}
if (master->get_unmapped_area)
slave->mtd.get_unmapped_area = part_get_unmapped_area;
if (master->read_oob)
slave->mtd.read_oob = part_read_oob;
if (master->write_oob)
slave->mtd.write_oob = part_write_oob;
if (master->read_user_prot_reg)
slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
if (master->read_fact_prot_reg)
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
if (master->write_user_prot_reg)
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
if (master->lock_user_prot_reg)
slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
if (master->get_user_prot_info)
slave->mtd.get_user_prot_info = part_get_user_prot_info;
if (master->get_fact_prot_info)
slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
if (master->sync)
slave->mtd.sync = part_sync;
if (!partno && !master->dev.class && master->suspend && master->resume) {
slave->mtd.suspend = part_suspend;
slave->mtd.resume = part_resume;
}
if (master->writev)
slave->mtd.writev = part_writev;
if (master->lock)
slave->mtd.lock = part_lock;
if (master->unlock)
slave->mtd.unlock = part_unlock;
if (master->is_locked)
slave->mtd.is_locked = part_is_locked;
if (master->block_isbad)
slave->mtd.block_isbad = part_block_isbad;
if (master->block_markbad)
slave->mtd.block_markbad = part_block_markbad;
slave->mtd.erase = part_erase;
slave->master = master;
slave->offset = part->offset;
这两个结构体的读写函数有啥不同呢?待续。。。。。
2.内核加载ubi
mtdchar.c
mtdblock.c
加载mtd分区上的文件系统后,执行文件系统根目录的linuxrc(因为 setenv bootargs console=ttySAC0 noinitrd root=/dev/mtdblock3 init=/linuxrc)和init
见内核源码init/main.c init_post()
if (execute_command) { run_init_process(execute_command);//init=/linuxrc printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance.");
http://qiuye.iteye.com/blog/543595