Arch/arm/mach-s3c2410/mach-smdk2410.c
static int chip0_map[] = { 0 };
硬件信息
static struct mtd_partitionsmdk_default_nand_part[] = {
[0] = {
.name = "boot",
.size = SZ_128K + SZ_64K,
.offset = 0,
},
[1] = {
.name = "kernel",
.size = SZ_2M - SZ_128K - SZ_64K,
.offset = SZ_128K + SZ_64K,
},
[2] = {
.name = "rootfs",
.size = 62 * SZ_1M,
.offset = SZ_2M,
}
};
static struct s3c2410_nand_setsmdk_nand_sets[] = {
[0] = {
.name = "chip0",
.nr_chips = 1,
.nr_map = chip0_map,
.nr_partitions = ARRAY_SIZE(smdk_default_nand_part),
.partitions = smdk_default_nand_part
},
};
static void smdk_nand_select(structs3c2410_nand_set *set, int slot)
{
slot = set->nr_map[slot] & 3;
}
static struct s3c2410_platform_nandsmdk_nand_info = {
.tacls = 0,//80,
.twrph0 = 20,//80,
.twrph1 = 0,//80,
.nr_sets =ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
.select_chip =smdk_nand_select,
};
drivers/mtd/nand/s3c2410.c
static int s3c2410_nand_probe(struct device*dev)
{
…
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
pr_debug("initialising set%d (%p, info %p)\n",
setno, nmtd, info);
s3c2410_nand_init_chip(info,nmtd, sets);
nmtd->scan_res =nand_scan(&nmtd->mtd,
(sets) ? sets->nr_chips : 1);
if (nmtd->scan_res == 0) {
s3c2410_nand_add_partition(info, nmtd, sets);
}
if (sets != NULL)
sets++;
}
…
}
drivers/mtd/nand/s3c2410.c
static void s3c2410_nand_init_chip(structs3c2410_nand_info *info,
structs3c2410_nand_mtd *nmtd,
structs3c2410_nand_set *set)
{
struct nand_chip *chip = &nmtd->chip;
chip->IO_ADDR_R = (char*)info->regs + S3C2410_NFDATA;
chip->IO_ADDR_W = (char*)info->regs + S3C2410_NFDATA;
chip->hwcontrol =s3c2410_nand_hwcontrol;
chip->dev_ready =s3c2410_nand_devready;
chip->cmdfunc =s3c2410_nand_command;
chip->write_buf =s3c2410_nand_write_buf;
chip->read_buf =s3c2410_nand_read_buf;
chip->select_chip =s3c2410_nand_select_chip;
chip->chip_delay = 50;
chip->priv = nmtd;
chip->options = 0;
chip->controller =&info->controller;
nmtd->info = info;
nmtd->mtd.priv = chip;
nmtd->set = set;
if (hardware_ecc) {
chip->correct_data = s3c2410_nand_correct_data;
chip->enable_hwecc = s3c2410_nand_enable_hwecc;
chip->calculate_ecc =s3c2410_nand_calculate_ecc;
chip->eccmode = NAND_ECC_HW3_512;
chip->autooob = &nand_hw_eccoob;
} else {
//---------modify by liyutai-----------------//
// chip->eccmode = NAND_ECC_SOFT;
chip->eccmode = NAND_ECC_NONE;
//-------------------------------------------//
}
}
Drivers/mtd/nand/nand_ids.c
struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;
};
struct nand_flash_dev nand_flash_ids[] = {
…
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
…
}
static struct nand_oobinfo nand_oob_16 = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = { {8, 8} }
};
drivers/mtd/nand/nand_base.c
int nand_scan (struct mtd_info *mtd, intmaxchips)
{
…
if (!this->select_chip)
this->select_chip =nand_select_chip;
if (!this->write_byte)
this->write_byte = busw ?nand_write_byte16 : nand_write_byte;
if (!this->read_byte)
this->read_byte = busw ?nand_read_byte16 : nand_read_byte;
if (!this->write_word)
this->write_word =nand_write_word;
if (!this->read_word)
this->read_word =nand_read_word;
if (!this->block_bad)
this->block_bad =nand_block_bad;
if (!this->block_markbad)
this->block_markbad =nand_default_block_markbad;
if (!this->write_buf)
this->write_buf = busw ?nand_write_buf16 : nand_write_buf;
if (!this->read_buf)
this->read_buf = busw ?nand_read_buf16 : nand_read_buf;
if (!this->verify_buf)
this->verify_buf = busw ?nand_verify_buf16 : nand_verify_buf;
if (!this->scan_bbt)
this->scan_bbt =nand_default_bbt;
…
if (!mtd->name) mtd->name= nand_flash_ids[i].name;
this->chipsize =nand_flash_ids[i].chipsize << 20;
…
mtd->erasesize =nand_flash_ids[i].erasesize; //0x4000
mtd->oobblock =nand_flash_ids[i].pagesize; //512
mtd->oobsize =mtd->oobblock / 32; //16
busw =nand_flash_ids[i].options & NAND_BUSWIDTH_16; //0
…
/* Calculate the address shiftfrom the page size */
this->page_shift =ffs(mtd->oobblock) - 1; //9
this->bbt_erase_shift =this->phys_erase_shift = ffs(mtd->erasesize) - 1; //15
this->chip_shift =ffs(this->chipsize) - 1; //26
/* Set the bad block position*/
this->badblockpos =mtd->oobblock > 512 ?
NAND_LARGE_BADBLOCK_POS: NAND_SMALL_BADBLOCK_POS; // NAND_SMALL_BADBLOCK_POS 5
/* Get chip options, preservenon chip based options */
this->options &=~NAND_CHIPOPTIONS_MSK;
this->options |=nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
/* Set this as a default. Boarddrivers can override it, if neccecary */
this->options |=NAND_NO_AUTOINCR;
…
this->erase_cmd= single_erase_cmd;
/* Allocate buffers, if neccecary */
if (!this->oob_buf) {
size_t len;
len = mtd->oobsize <<(this->phys_erase_shift - this->page_shift); //512
this->oob_buf = kmalloc(len, GFP_KERNEL);
if (!this->oob_buf) {
printk (KERN_ERR"nand_scan(): Cannot allocate oob_buf\n");
return -ENOMEM;
}
this->options |=NAND_OOBBUF_ALLOC;
}
if (!this->data_buf) {
size_t len;
len = mtd->oobblock +mtd->oobsize; //512+16
this->data_buf = kmalloc(len, GFP_KERNEL);
if (!this->data_buf) {
if (this->options& NAND_OOBBUF_ALLOC)
kfree(this->oob_buf);
printk (KERN_ERR"nand_scan(): Cannot allocate data_buf\n");
return -ENOMEM;
}
this->options |=NAND_DATABUF_ALLOC;
}
/* Store the number of chips and calctotal size for mtd */
this->numchips = i;
mtd->size = i * this->chipsize;
/* Convert chipsize to number of pagesper chip -1. */
this->pagemask = (this->chipsize>> this->page_shift) - 1; //0x1ffff
/* Preset the internal oob buffer */
memset(this->oob_buf, 0xff,mtd->oobsize << (this->phys_erase_shift - this->page_shift));
…
this->autooob= &nand_oob_16;
…
mtd->oobavail= mtd->oobsize - (this->autooob->eccbytes + 1); //9
…
this->eccsize = 256; /* set default eccsize */
this->eccbytes = 3;
…
this->eccmode= NAND_ECC_NONE;
…
mtd->eccsize= this->eccsize;
…
this->eccsteps= 1;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH |MTD_ECC;
mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_ecc = nand_read_ecc;
mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->readv = NULL;
mtd->writev = nand_writev;
mtd->writev_ecc = nand_writev_ecc;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = NULL;
mtd->resume = NULL;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad =nand_block_markbad;
/* and make the autooob the default one*/
memcpy(&mtd->oobinfo, this->autooob,sizeof(mtd->oobinfo));
mtd->owner = THIS_MODULE;
/* Build bad block table */
return this->scan_bbt (mtd);
}
drivers/mtd/nand/nand_bbt.c
static uint8_t scan_ff_pattern[] = { 0xff,0xff };
static struct nand_bbt_descr smallpage_memorybased= {
.options = 0,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
};
int nand_default_bbt (struct mtd_info *mtd)
{
…
/* Is a flash based bad block table requested ? */
if (this->options & NAND_USE_FLASH_BBT) {
/* Use the default patterndescriptors */
if (!this->bbt_td) {
this->bbt_td =&bbt_main_descr;
this->bbt_md =&bbt_mirror_descr;
}
if (!this->badblock_pattern){
this->badblock_pattern = (mtd->oobblock > 512) ?
&largepage_flashbased : &smallpage_flashbased;
}
} else {
this->bbt_td = NULL;
this->bbt_md = NULL;
if (!this->badblock_pattern){
this->badblock_pattern = (mtd->oobblock > 512) ?
&largepage_memorybased : &smallpage_memorybased; // smallpage_memorybased
}
}
return nand_scan_bbt (mtd, this->badblock_pattern);
}
int nand_scan_bbt (struct mtd_info *mtd,struct nand_bbt_descr *bd)
{
…
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
len = mtd->size >> (this->bbt_erase_shift + 2); //64M >> 17 = 512
/* Allocate memory (2bit per block) */
this->bbt = kmalloc (len, GFP_KERNEL);
if (!this->bbt) {
printk (KERN_ERR"nand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
/* Clear the memory bad block table */
memset (this->bbt, 0x00, len);
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
*/
if (!td)
return nand_memory_bbt(mtd,bd);
}
static int nand_memory_bbt (struct mtd_info*mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
/* Ensure that we only scan for the pattern and nothing else */
bd->options = 0;
create_bbt (mtd, this->data_buf, bd, -1);
return 0;
}
static void create_bbt (struct mtd_info*mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
{
…
if (bd->options &NAND_BBT_SCANALLPAGES)
len = 1 <<(this->bbt_erase_shift - this->page_shift);
else {
if (bd->options &NAND_BBT_SCAN2NDPAGE)
len = 2;
else
len = 1; //here
}
scanlen = mtd->oobblock + mtd->oobsize; //512 + 16 = 528
readlen = len * mtd->oobblock; //512
ooblen = len * mtd->oobsize; //16
if (chip == -1) {
/* Note that numblocks is 2 *(real numblocks) here, see i+=2 below as it
* makes shifting and maskingless painful */
numblocks = mtd->size>> (this->bbt_erase_shift - 1); //64M >> 14 = 4096
startblock = 0;
from = 0;
}
for (i = startblock; i < numblocks;){
nand_read_raw (mtd, buf, from,readlen, ooblen);
for (j = 0; j < len; j++) {
if (check_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
this->bbt[i>> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i>> 1, (unsigned int) from);
break;
}
}
i += 2;
from += (1 <<this->bbt_erase_shift);
}
}
Drivers/mtd/nand/nand_base.c
int nand_read_raw (struct mtd_info *mtd,uint8_t *buf, loff_t from, size_t len, size_t ooblen)
{
struct nand_chip *this = mtd->priv;
int page = (int) (from >> this->page_shift); //from >> 9
int chip = (int) (from >> this->chip_shift); //from >> 26
int sndcmd = 1;
int cnt = 0;
int pagesize = mtd->oobblock + mtd->oobsize; //512 + 16 = 528
int blockcheck = (1 <<(this->phys_erase_shift - this->page_shift)) - 1; //63
…
/* Add requested oob length */
len += ooblen;
while (len) {
if (sndcmd)
this->cmdfunc (mtd,NAND_CMD_READ0, 0, page & this->pagemask);
sndcmd = 0;
this->read_buf (mtd,&buf[cnt], pagesize);
len -= pagesize;
cnt += pagesize;
page++;
if (!this->dev_ready)
udelay(this->chip_delay);
else
while(!this->dev_ready(mtd));
/* Check, if the chip supportsauto page increment */
if (!NAND_CANAUTOINCR(this) ||!(page & blockcheck))
sndcmd = 1;
}
…
}
static int check_pattern (uint8_t *buf, intlen, int paglen, struct nand_bbt_descr *td)
{
int i, end;
uint8_t *p = buf;
end = paglen + td->offs;
if (td->options & NAND_BBT_SCANEMPTY) {
for (i = 0; i < end; i++) {
if (p[i] != 0xff)
return -1;
}
}
p += end;
/* Compare the pattern */
for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
}
p += td->len;
end += td->len;
if (td->options & NAND_BBT_SCANEMPTY) {
for (i = end; i < len; i++){
if (*p++ != 0xff)
return -1;
}
}
return 0;
}
今天发现多了很多连续坏块,查文件系统没发现什么错误,查了很久,发现坏块扫描扫了整块NAND,报错的位置正好在kernel的位置,把kernel位置全部擦除,恢复正常