CFI查询(五)

2024-04-06 05:08
文章标签 查询 cfi

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



http://www.chinasem.cn/article/879071

相关文章

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复

mysql查询使用_rowid虚拟列的示例

《mysql查询使用_rowid虚拟列的示例》MySQL中,_rowid是InnoDB虚拟列,用于无主键表的行ID查询,若存在主键或唯一列,则指向其,否则使用隐藏ID(不稳定),推荐使用ROW_NUM... 目录1. 基本查询(适用于没有主键的表)2. 检查表是否支持 _rowid3. 注意事项4. 最佳实

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)

《MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)》掌握多表联查(INNERJOIN,LEFTJOIN,RIGHTJOIN,FULLJOIN)和子查询(标量、列、行、表子查询、相关/非相关、... 目录第一部分:多表联查 (JOIN Operations)1. 连接的类型 (JOIN Types)

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt