Chinaunix首页 | 论坛 | 博客
  • 博客访问: 647118
  • 博文数量: 156
  • 博客积分: 4833
  • 博客等级: 上校
  • 技术积分: 1554
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-21 19:36
文章分类

全部博文(156)

文章存档

2016年(2)

2013年(1)

2012年(13)

2011年(30)

2010年(46)

2009年(29)

2008年(23)

2007年(12)

分类: LINUX

2009-07-26 12:10:11

mtd/drivers/mtd/chips cfi_cmdset_0002.c,1.93,1.94

dvrabel at infradead.org
Tue Jan 27 05:16:22 EST 2004
  • Previous message:
  • Next message:
  • Messages sorted by:

Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv12948/drivers/mtd/chips

Modified Files:
cfi_cmdset_0002.c
Log Message:
Fixes erase-suspend on AMD command set chips:
- Erase suspend resume command must be written to the block to be resumed.
- When erasing DQ2 must a) be read from the erase in progress block
b) doesn't indicate that an erase has been suspended. DQ6 is the toggle
bit to check.
- Currently erase-suspend-program does work. It sometimes fails to erase
the block completely. So erase-suspend-program has been disabled for now.
Note that this severly reduces write performance when used with (for
example) JFFS2 but at least it works.


Index: cfi_cmdset_0002.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0002.c,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -r1.93 -r1.94
--- cfi_cmdset_0002.c 20 Nov 2003 08:39:35 -0000 1.93
+++ cfi_cmdset_0002.c 27 Jan 2004 10:16:20 -0000 1.94
@@ -375,6 +375,9 @@
printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
cfi->fast_prog = 0;
}
+ /* FIXME: erase-suspend-program is broken. See
+ */
+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");


/* does this chip have a secsi area? */
@@ -499,27 +502,37 @@
return 0;

case FL_ERASING:
+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
+ goto sleep;
+
if (!(mode == FL_READY || mode == FL_POINT
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
goto sleep;

+ oldstatus = cfi_read(map, adr);
+ status = cfi_read(map, adr);
+ if ((oldstatus ^ status) & dq2) {
+ printk(KERN_ERR "Can't suspend erase -- block in progress\n");
+ goto sleep;
+ }
+
/* Erase suspend */
/* FIXME - is there a way to verify suspend? */
- cfi_write(map, CMD(0xB0), adr);
+ cfi_write(map, CMD(0xB0), chip->in_progress_block_addr);
chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1;
for (;;) {
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- if (((oldstatus ^ status) & dq2) == dq2)
+ oldstatus = cfi_read(map, chip->in_progress_block_addr);
+ status = cfi_read(map, chip->in_progress_block_addr);
+ if (((oldstatus ^ status) & dq6) == 0)
break;

if (time_after(jiffies, timeo)) {
/* Urgh. Resume and pretend we weren't here. */
/* FIXME - is there a way to verify resume? */
- cfi_write(map, CMD(0x30), adr);
+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
chip->state = FL_ERASING;
chip->oldstate = FL_READY;
printk(KERN_ERR "Chip not ready after erase "
@@ -533,7 +546,7 @@
/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
So we can just loop here. */
}
- chip->state = FL_STATUS;
+ chip->state = FL_READY;
return 0;

case FL_POINT:
@@ -561,7 +574,7 @@
switch(chip->oldstate) {
case FL_ERASING:
chip->state = chip->oldstate;
- cfi_write(map, CMD(0x30), adr);
+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
chip->oldstate = FL_READY;
chip->state = FL_ERASING;
break;
@@ -1506,7 +1519,8 @@

chip->state = FL_ERASING;
chip->erase_suspended = 0;
-
+ chip->in_progress_block_addr = adr;
+
cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((chip->erase_time*HZ)/(2*1000));
@@ -1738,6 +1752,7 @@

chip->state = FL_ERASING;
chip->erase_suspended = 0;
+ chip->in_progress_block_addr = adr;

cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);



  • Previous message:
  • Next message:
  • Messages sorted by:



////////////////////////////////
////////////////////////////////
,在使用AMD/Fujitsu Nor Flash类型的所有嵌入式系统中,只要内核对于Flash配置正确,都会打印此信息。
   该信息来自drivers/mtd/chips/cfi_cmdset_0002.c文件cfi_amdstd_setup函数末尾处。
具体调用流程如下(符合CFI接口标准的FLASH初始化流程):
drivers/mtd/maps/yourdriver.c:yourdriver_init (Flash驱动一般的入口方式,也有使用
platform device方式的,此处不论。)
|
v
drivers/mtd/chips/chipreg.c:do_map_probe
|
v
drivers/mtd/chips/cfi_probe.c:cfi_probe
|
v
drivers/mtd/chips/gen_probe.c:mtd_do_chip_probe
|
v
drivers/mtd/chips/gen_probe.c:check_cmd_set
|
v
drivers/mtd/chips/cfi_cmdset_0002.c:cfi_cmdset_0002
|
v
drivers/mtd/chips/cfi_cmdset_0002.c:cfi_amdstd_setup



cfi_amdstd_setup函数实现如下(2.6.22内核):
static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
{
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned long devsize = (1<cfiq->DevSize) * cfi->interleave;
        unsigned long offset = 0;
        int i,j;

        printk(KERN_NOTICE "number of %s chips: %d\n",
               (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
        /* Select the correct geometry setup */
        mtd->size = devsize * cfi->numchips;

        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                                    * mtd->numeraseregions, GFP_KERNEL);
        if (!mtd->eraseregions) {
                printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n";
                goto setup_err;
        }

        for (i=0; icfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo >> & ~0xff) * cfi->interleave;
                ernum = (cfi->cfiq->EraseRegionInfo & 0xffff) + 1;

                if (mtd->erasesize < ersize) {
                        mtd->erasesize = ersize;
                }
                for (j=0; jnumchips; j++) {
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
                }
                offset += (ersize * ernum);
        }
        if (offset != devsize) {
                /* Argh */
                printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
                goto setup_err;
        }
#if 0
        // debug
        for (i=0; inumeraseregions;i++){
                printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
                       i,mtd->eraseregions.offset,
                       mtd->eraseregions.erasesize,
                       mtd->eraseregions.numblocks);
        }
#endif

        /* FIXME: erase-suspend-program is broken.  See
           ... ecember/009001.html */
        printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n";

        __module_get(THIS_MODULE);
        return mtd;

setup_err:
        if(mtd) {
                kfree(mtd->eraseregions);
                kfree(mtd);
        }
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        return NULL;
}


注意函数末尾处的printk调用打印,这个打印并不依赖于任何其他宏定义,它只是一个警告。要解释一下,那么就是:
内核flash代码没有对flash erase-suspend方式进行支持。
如果你阅读过某一flash手册(其实所有CFI接口规范的flash手册都大同小异),你会看到
flash有一个suspend命令,可以对当前执行的命令进行挂起,还有一个resume命令,可以启动之前挂起的flash操作。
flash的擦除是按block(1 block 一般等于64kB)方式擦除的。那么以上的意思就是在flash擦除过程中内核代码不支持挂起再启动的操作,即如果发出命令擦除10个block,那么内核要么被中断擦除操作(ctrl+c),要么全部擦除完成;不支持我先擦除7个block,挂起一会,再擦除剩下的3个block。
   实际上,这种方式不会对flash的正常工作造成任何影响,一般我们自己在写flash驱动时,大多也不支持erase-suspend操作,更进一步,大多数时候suspend, resume命令根本就不使用!

   综上所述,以上打印的警告信息完全可以忽略不计,而非内核不提供flash驱动。为避免用户“紧张”,你完全可以将这个打印信息注释掉!








阅读(1893) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~