//以下仅是本人的一些的理解 /* Marvell 98DX51xx / 98DX81xx 系列交换芯片 内部初始化 现在一些高端防火墙,流量管理等工业级网络设备使用的交换芯片几乎都来自于broadcom或marvell公司,一些高端的交换芯片售价高达数千美金,再加上几颗专用于处理报文业务的CPU(多核),还要有一颗用于管理控制系统资源(承载linux)的CPU, 这就是系统的核心的架构, 其他的外设都围绕以上三者展开.一般的硬件成本在几万美金以上。 现在的千兆/万兆以太网三层交换机等设备用也会使用一些高端的交换芯片,这类交换芯片内部一般会集成CPU ,外部再加上FPGA或CPU的配合, 就可组成产品的硬件核心, 硬件成本为几白美金之上。 无论是哪种网络设备产品, 都离不开交换芯片(或称为数据包处理芯片 Packet processor)或者的使用, 而在交换芯片的市场上, 引领者无疑是Broadcom 和 Marvell .如今随着千兆/万兆以太网的推广, 以太网的市场发展一日千里, 交换芯片也将承载更强更多的业务能力和管理能力,所以理解并熟悉以太网交换芯片的驱动将是驱动工程师的重要工作之一. 我们的系统就使用2颗marvell 交换芯片98DX5128 和98DX8110. 98DX5128 集成了24个千兆端口 和 4个万兆端口, 管理接口为PCI-Express. 98DX8110 集成了10 个万兆端口.管理接口为PCI-Express. 实现marvell 交换芯片的驱动是基于marvell的SDK,SDK中提供了操作该芯片的API,其中硬件初始化部分是比较重要的阶段,在后续的开发过程中很多bug的出现都可能关联在此,需要驱动工作者对此有一定的理解。而且这部分不会在芯片的datasheet 上给以说明,只能靠对SDK中代码的阅读,来大致理解整个过程. 初始化过程不同于其他的配置过程,如自动协商,地址学习,PVID,VLAN表配置,转发规则等等.这些只要根据datasheet上的相应描述,找到SDK中的相应API ,经过封装后调用即可. SDK 框架如此庞大, 是为了做到兼容不同的芯片。增加了结构的复杂性,但实现了最大的兼容性。 阅读SDK是有非常难度的, 刚接触linux时候,感觉linux的kernel就够复杂了. 看过了这套SDK再看linux, 你会感觉linux的driver的脉络是那么清晰,她的架构都是那么有层次感,无论是总线还是设备,几乎每个module 都可以按照一个架构思路来分析和观察。但是SDK 中没有结构感, 经常能见到一个 .c 文件中就装了上万行的代码, 其中一大半用来实现复用, 细细品来,真的把兼容性做到了极致。 SDK 是我们在我们自定义的架构下,根据我们的操作,来实现硬件芯片的 drive ,但是这个driver 完全是在用户层上实现的。 不同与 linux 内核中的driver 。 SDK 不选择添加到linux driver 中的原因是, 因为需要经常调试,如果添加在driver 中,那么每次修改后都要重新 make kernel , 假如新的kernel运行不起来,只能用串口或网口在bootloader阶段重新load,这个过程非常耗时费力。根据SDK 中提供的API , 使得驱动工程师可以在用户层修改各种硬件配置参数,修改好后只需compile 和 install 就可以,进而在shell中直接操作硬件寄存器。 SDK 中提供了特有的,针对具体的芯片的软件接口,这种接口的底层一般都是经过严密封装的,几乎无法看到是怎么样具体操作寄存器的(也没必要去关心)。 SDK 的使用也是需要得到授权的,一款高端芯片的授权费用可能高达数十万美金。如此高昂的价格在于它集成了多少优秀的工程师多少年的汗水的智慧,是一个商业公司的核心技术的结晶。 那么对于有着这样价值的代码, 有些部分是着重阅读的, 想把SDK中的代码完全读完读懂几乎是不可能的,也完全没有必要,我们的目的只是如下: 一,软件兼容性. 我们可以观察它是怎么使用一套代码兼容数十种不同型号的芯片。这样可以使得我们实现API时,实现代码更精炼,更有兼容性. 二,SDK不是针对某一个特定芯片而做,在实际使用中或多或少会有些需要修改的地方,这就需要对关键的部分有所了解,这样在出现bug的时候可以快速定位,进而解决(这也是实际工作中老板支付你工资的原因). 三,目前很多国外的芯片, 性能和稳定性的确高于国产芯片. 就比如在交换芯片,只有broadcom,marvell. 但一个小公司若想使用, 难以得到厂商的技术支持, 如果这种芯片在国内市场上还没有多数使用,找不到参考资料,那 只能阅读芯片的英文datasheet来学习, 再到理解这款芯片, 这是需要很长时间的, 不仅开发周期变长,还有很多很多不可预知的风险, 这对一个小公司的生存是种考验. 但若要等到市场上开始接受了这款芯片, 可以获取更多的信息和资料时, 很可能失去了先发优势, 延误了市场的最佳战机.即便产品研发成功, 销售又成了压力. 其实这点痛苦了我很久, 所以我希望我今天的一点点理解和简陋的表达, 能为将来某位苦恼在这款芯片的嵌入式linux驱动工作者提供那怕一点点帮助. 所谓前人栽树后人乘凉, 毕竟开放和分享是这个时代的主流.如果哪位前辈能够给我以指导,我将不胜感激。 SDK 的使用: 一,既然此 driver 也是linux 的一部分,肯定是需要Makefile来组织,来使其融入linux。 在Makefile 中也要有TARGET,export变量,INCLUDES, LIB_PATH, ,LIBCPSS,CFLAGS等的描述, 比如在export 中就需要有相应的宏定义, 程序在运行时就可以根据定义的宏,来执行 #ifdef xxx等判断。 执行特定芯片需要执行的部分。 如果要使用此SDK支持的其他芯片,那么只需要修改Makefile,而不用改动SDK . 二, SDK 是提供API给我们使用的, 那么我们应该设计一套软件架构来作为承载, 可将我们的软件做为一个守护进程 , 完成自身的初始化后, 等待shell 的调用, 根据具体的命令,来调用SDK中的具体API,实现相应的配置。 */ /* by: 韩大卫 @吉林师范大学 转载请标明出处 */ /* 芯片硬件初始化的过程为如下代码, 不足实际代码的1%. 省略了很多无关的部分,只为澄清脉络. 本文仅是展开硬件初始化部分的代码. 关于此芯片的具体功能描述或数据包处理流程等, 请参考作者的其他文章. */ api的使用 :rc = cpssInitSystem(1,3,0); cpssInitSystem() 定义如下: * INPUTS: * boardIdx - The index of the board to be initialized from the board list. * boardRevId - Board revision Id. * reloadEeprom - Whether the Eeprom should be reloaded when * corePpHwStartInit() is called. GT_STATUS cpssInitSystem ( IN GT_U32 boardIdx, IN GT_U32 boardRevId, IN GT_U32 reloadEeprom } { …. GT_BOARD_LIST_ELEMENT *pBoardInfo; /* Holds the board information*/ GT_BOARD_CONFIG_FUNCS boardCfgFuncs; /* Board specific configuration functions. */ /* GT_BOARD_LIST_ELEMENT 定义是: typedef struct { FUNCP_REGISTER_BOARD_FUNCS registerFunc; GT_CHAR boardName[GT_BOARD_LIST_STRING_LEN_CNS]; GT_U8 numOfRevs; GT_CHAR boardRevs[GT_BOARD_LIST_NUM_OF_BORAD_INITS_CNS][GT_BOARD_LIST_STRING_LEN_CNS]; }GT_BOARD_LIST_ELEMENT; GT_BOARD_CONFIG_FUNCS 包含了芯片特定的控制功能,定义如下: typedef struct { FUNCP_GET_BOARD_MEMORY_INFO boardGetMemInfo; FUNCP_GET_BOARD_INFO boardGetInfo; FUNCP_BEFORE_PHASE1_CONFIG boardBeforePhase1Config; FUNCP_GET_PP_PHASE1_PARAMS boardGetPpPh1Params; FUNCP_AFTER_PHASE1_CONFIG boardAfterPhase1Config; FUNCP_GET_PP_PHASE2_PARAMS boardGetPpPh2Params; FUNCP_AFTER_PHASE2_CONFIG boardAfterPhase2Config; FUNCP_GET_PP_LOGICAL_INIT_PARAMS boardGetPpLogInitParams; FUNCP_GET_LIB_INIT_PARAMS boardGetLibInitParams; FUNCP_AFTER_INIT_CONFIG boardAfterInitConfig; FUNCP_GET_PP_REG_CFG_LIST boardGetPpRegCfgList; FUNCP_GET_STACK_CONFIG_PARAMS boardGetStackConfigParams; FUNCP_GET_MNG_PORT_NAME boardGetMngPortName; FUNCP_AFTER_STACK_READY_CONFIG boardAfterStackReadyConfig; }GT_BOARD_CONFIG_FUNCS; 函数的功能概括如下: * Fields: * boardGetMemInfo - Returns memory size for the board. * boardGetInfo - Returns general board information. * boardGetXbarCfgParams - Returns parameters for the xbarSysConfig() * function. * boardGetPpPh1Params - Returns parameters for the * corePpHwPhase1Init() function. * boardGetFaPh1Params - Returns parameters for the * coreFaHwPhase1Init() function. * boardGetXbarPh1Params - Returns parameters for the * coreXbarHwPhase1Init() function. * boardAfterPhase1Config - Board specific configurations that should * be done after core phase1 initialization. * boardGetPpPh2Params - Returns parameters for the * corePpHwPhase2Init() function. * boardGetFaPh2Params - Returns parameters for the * coreFaHwPhase2Init() function. * boardGetXbarPh2Params - Returns parameters for the * coreXbarHwPhase2Init() function. * boardAfterPhase2Config - Board specific configurations that should * be done after core phase2 initialization. * boardGetSysCfgParams - Returns parameters for the sysConfig() * function. * boardGetPpLogInitParams - Returns parameters for the * sysPpLogicalInit() function. * boardGetLibInitParams - Returns parameters for Tapi libraries * initialization. * afterInitConfig - Board specific configurations that should * be done after board initialization. * * boardGetPpRegCfgList - The following pointers were added to * boardGetFaRegCfgList support stack. * boardGetStackConfigParams * boardGetMngPortName * boardAfterStackReadyConfig */ ... pBoardInfo = &(boardsList[boardIdx – 1]); /* boardsList 中我们关心的部分定义如下: GT_BOARD_LIST_ELEMENT boardsList[] = ... 根据cpssInitSystem(1,3,0) 中的 参数1 找到此的成员。 // //根据参数 3 要与此成员中的 “3” 对应。 {gtDbDx348GE4HGSBoardReg ,"DB-DX3-GP" ,3,{"Rev 0.1", "Rev 0.2 - RDE tests", "Rev 0.3 - FC OFF"}}, ... gtDbDx348GE4HGSBoardReg 定义是: GT_STATUS gtDbDx348GE4HGSBoardReg ( IN GT_U8 boardRevId, OUT GT_BOARD_CONFIG_FUNCS *boardCfgFuncs ) { if(boardCfgFuncs == NULL) { return GT_FAIL; } boardCfgFuncs->boardGetInfo = getBoardInfo; /*boardCfgFuncs->boardGetCoreCfgPh1Params = getCoreSysCfgPhase1;*/ boardCfgFuncs->boardGetPpPh1Params = getPpPhase1Config; boardCfgFuncs->boardAfterPhase1Config = configBoardAfterPhase1; /*boardCfgFuncs->boardGetCoreCfgPh2Params = getCoreSysCfgPhase2;*/ boardCfgFuncs->boardGetPpPh2Params = getPpPhase2Config; boardCfgFuncs->boardAfterPhase2Config = configBoardAfterPhase2; /*boardCfgFuncs->boardGetSysCfgParams = getSysConfigParams;*/ boardCfgFuncs->boardGetPpLogInitParams = getPpLogicalInitParams; boardCfgFuncs->boardGetLibInitParams = getTapiLibInitParams; boardCfgFuncs->boardAfterInitConfig = afterInitBoardConfig; /*boardCfgFuncs->boardGetUserPorts = getUserPorts;*/ return GT_OK; } 用特定的,针对此芯片的配置函数 填充结构体 boardCfgFuncs中的成员函数。 此后的每一步初始化过程中, 具体的配置函数都是基于以上。 */ ... /* Get board specific functions accordingly to board rev. id */ rc = pBoardInfo->registerFunc((GT_U8)boardRevId, &boardCfgFuncs); // 此时registerFunc() 的实现函数就是gtDbDx348GE4HGSBoardReg rc = appDemoInitGlobalModuls(numOfMem, reloadEeprom); /* appDemoInitGlobalModuls 定义如下: static GT_STATUS appDemoInitGlobalModuls ( IN GT_U32 numOfMemBytes, IN GT_U32 reloadEeprom ) { GT_STATUS rc; /* To hold funcion return code */ GT_U32 i; /* Loop index */ /* Initialize memory pool. It must be done before any memory allocations */ rc = osMemInit(numOfMemBytes, GT_TRUE); if (rc != GT_OK) { return rc; } /* save reload eeprom for future use */ gReloadEeprom = (reloadEeprom == 1 ? GT_TRUE : GT_FALSE); /* Initialize the PP array with default parameters */ for (i = 0; i < PRV_CPSS_MAX_PP_DEVICES_CNS; i++) { osMemSet(&appDemoPpConfigList[i], 0, sizeof(appDemoPpConfigList[i])); appDemoPpConfi
Marvell 98DX51xx / 98DX81xx 系列交换芯片 内部初始化
最新推荐文章于 2023-04-11 22:00:58 发布
本文详细介绍了Marvell 98DX51xx / 98DX81xx 交换芯片的内部初始化过程,包括如何使用SDK进行硬件配置,以及初始化涉及的API、结构体和配置函数。通过理解SDK的工作原理,可以更好地应对驱动开发中的问题和挑战。
摘要由CSDN通过智能技术生成