CFI查询(五)

接着上一篇

1、我们以前说过,CFI闪存芯片还可能提供“主算法扩充查询表”和“次算法扩充查询表”,我们对此尚未进行查询。

回到mtd_do_chip_probe函数的代码中,下面就是对这两个表的补充查询。

struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
{
struct mtd_info *mtd = NULL;
struct cfi_private *cfi;


/* First probe the map to see if we have CFI stuff there. */
cfi = genprobe_ident_chips(map, cp);
这一部分是前几篇的主题。

if (!cfi)
return NULL;


map->fldrv_priv = cfi;
/* OK we liked it. Now find a driver for the command set it talks */


mtd = check_cmd_set(map, 1); /* First the primary cmdset */
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */

if (mtd)
return mtd;

通过两次check_cmd_set函数,读入上述的主、次两个表,也就是对芯片所支持操作规程的附加参数。源码如下:

static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;

if (type == P_ID_NONE || type == P_ID_RESERVED)
return NULL;


switch(type){
/* Urgh. Ifdefs. The version with weak symbols was
* _much_ nicer. Shame it didn't seem to work on
* anything but x86, really.
* But we can't rely in inter_module_get() because
* that'd mean we depend on link order.
*/
#ifdef
CONFIG_MTD_CFI_INTELEXT      intel的
case 0x0001:
case 0x0003:
return cfi_cmdset_0001(map, primary);
#endif
#ifdef CONFIG_MTD_CFI_AMDSTD      AMD的
case 0x0002:
return cfi_cmdset_0002(map, primary);
#endif
#ifdef CONFIG_MTD_CFI_STAA
        case 0x0020:
return cfi_cmdset_0020(map, primary);
#endif
}


return cfi_cmdset_unknown(map, primary);
}





printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");

kfree(cfi->cfiq);
kfree(cfi);
map->fldrv_priv = NULL;
return NULL;
}

2、这里是根据上面的函数和假设调用如下函数:

/* This routine is made available to other mtd code via
 * inter_module_register.  It must only be accessed through
 * inter_module_get which will bump the use count of this module.  The
 * addresses passed back in cfi are valid as long as the use count of
 * this module is non-zero, i.e. between inter_module_get and
 * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
 */
struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
__u32 base = cfi->chips[0].start;


if (cfi->cfi_mode == CFI_MODE_CFI) {
/* 
* It's a real CFI chip, not one for which the probe
* routine faked a CFI structure. So we read the feature
* table from it.
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;对应下面的数据结构源码。
int ofs_factor = cfi->interleave * cfi->device_type;


//printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
if (!adr)
return NULL;


/* Switch it into Query Mode */
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);


extp = kmalloc(sizeof(*extp), GFP_KERNEL);
if (!extp) {
printk(KERN_ERR "Failed to allocate memory\n");
return NULL;
}

/* Read in the Extended Query Table */
for (i=0; i<sizeof(*extp); i++) {
((unsigned char *)extp)[i] = 
cfi_read_query(map, (base+((adr+i)*ofs_factor)));
}

if (extp->MajorVersion != '1' || 
   (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
printk(KERN_WARNING "  Unknown IntelExt Extended Query "
      "version %c.%c.\n",  extp->MajorVersion,
      extp->MinorVersion);
kfree(extp);
return NULL;
}

/* Do some byteswapping if necessary */
extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);

#ifdef DEBUG_CFI_FEATURES
/* Tell the user about it in lots of lovely detail */
cfi_tell_features(extp);
#endif


if(extp->SuspendCmdSupport & 1) {
//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
      "erase on write disabled.\n");
extp->SuspendCmdSupport &= ~1;
#else
printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
#endif
}
/* Install our own private info structure */
cfi->cmdset_priv = extp;
}


for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
cfi->chips[i].ref_point_counter = 0;
}


map->fldrv = &cfi_intelext_chipdrv;

/* Make sure it's in read mode */
cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_intelext_setup(map);这个函数为Intel闪存板块创建一个mtd_info数据结构。源码在下面:
}

从扩充信息块中读入的信息保存在一个cfi_pri_intelext数据结构中,而cfi_private数据结构中的指针cmdset_priv则指向这个数据结构。


/* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */

struct cfi_pri_intelext {
  __u8  pri[3];
  __u8  MajorVersion;
  __u8  MinorVersion;
  __u32 FeatureSupport;
  __u8  SuspendCmdSupport;
  __u16 BlkStatusRegMask;
  __u8  VccOptimal;
  __u8  VppOptimal;
  __u8  NumProtectionFields;
  __u16 ProtRegAddr;
  __u8  FactProtRegSize;
  __u8  UserProtRegSize;
} __attribute__((packed));

3、紧接着上面的函数调用,此为函数源码。

此函数为Intel闪存板块创建一个mtd_info数据结构。结构中的信息来自两个方面。第一,我们已经知道用的是Intel芯片,所以芯片类型为MTD_NORFLASH。此外,结构中的诸多函数指针也都指向针对Intel芯片的操作函数。


static struct mtd_info *cfi_intelext_setup(struct map_info *map)
{
struct cfi_private *cfi = map->fldrv_priv;
struct mtd_info *mtd;
unsigned long offset = 0;
int i,j;
unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;


mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);


if (!mtd) {
printk(KERN_ERR "Failed to allocate memory for MTD device\n");
goto setup_err;
}


memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;芯片类型
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_ERR "Failed to allocate memory for MTD erase region info\n");
goto setup_err;
}

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


if (mtd->erasesize < ersize) {
mtd->erasesize = ersize;
}
for (j=0; j<cfi->numchips; 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;
}


for (i=0; i<mtd->numeraseregions;i++){
printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
      i,mtd->eraseregions[i].offset,
      mtd->eraseregions[i].erasesize,
      mtd->eraseregions[i].numblocks);
}


/* Also select the correct geometry setup too */ 指向Intel的芯片函数
mtd->erase = cfi_intelext_erase_varsize;
mtd->read = cfi_intelext_read;



if(map->point && map->unpoint){
mtd->point = do_point;
mtd->unpoint = do_unpoint;
}


#ifndef FORCE_WORD_WRITE
if ( cfi->cfiq->BufWriteTimeoutTyp ) {
printk("Using buffer write method\n" );
mtd->write = cfi_intelext_write_buffers;
} else {
#else
{
#endif
printk("Using word write method\n" );
mtd->write = cfi_intelext_write_words;
}
mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
mtd->sync = cfi_intelext_sync;
mtd->lock = cfi_intelext_lock;
mtd->unlock = cfi_intelext_unlock;
mtd->suspend = cfi_intelext_suspend;
mtd->resume = cfi_intelext_resume;

mtd->flags = MTD_CAP_NORFLASH;
map->fldrv = &cfi_intelext_chipdrv;
MOD_INC_USE_COUNT;
mtd->name = map->name;
return mtd;


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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值