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