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

相关文章

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

MYSQL关联关系查询方式

《MYSQL关联关系查询方式》文章详细介绍了MySQL中如何使用内连接和左外连接进行表的关联查询,并展示了如何选择列和使用别名,文章还提供了一些关于查询优化的建议,并鼓励读者参考和支持脚本之家... 目录mysql关联关系查询关联关系查询这个查询做了以下几件事MySQL自关联查询总结MYSQL关联关系查询

Java实现Elasticsearch查询当前索引全部数据的完整代码

《Java实现Elasticsearch查询当前索引全部数据的完整代码》:本文主要介绍如何在Java中实现查询Elasticsearch索引中指定条件下的全部数据,通过设置滚动查询参数(scrol... 目录需求背景通常情况Java 实现查询 Elasticsearch 全部数据写在最后需求背景通常情况下

查询Oracle数据库表是否被锁的实现方式

《查询Oracle数据库表是否被锁的实现方式》本文介绍了查询Oracle数据库表是否被锁的方法,包括查询锁表的会话、人员信息,根据object_id查询表名,以及根据会话ID查询和停止本地进程,同时,... 目录查询oracle数据库表是否被锁1、查询锁表的会话、人员等信息2、根据 object_id查询被

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

数据库oracle用户密码过期查询及解决方案

《数据库oracle用户密码过期查询及解决方案》:本文主要介绍如何处理ORACLE数据库用户密码过期和修改密码期限的问题,包括创建用户、赋予权限、修改密码、解锁用户和设置密码期限,文中通过代码介绍... 目录前言一、创建用户、赋予权限、修改密码、解锁用户和设置期限二、查询用户密码期限和过期后的修改1.查询用

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX