本文主要是介绍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;
}
这篇关于CFI查询(五)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!