技术积累BCM-SDK架构分析及源码移植-nios2平台移植

来源:互联网 发布:转格式软件哪个好 编辑:程序博客网 时间:2024/06/08 02:44

技术积累BCM-SDK架构分析及源码阅读

                                                                           ---北京华环电子 任晓亮 2016/01/09

希望:已经进入黑夜,黎明还会远吗?

经过两周的坚持不懈,SDK终于在Linux-V3.0版本编译通过。今天开始慢慢分析阅读源码。

一.SDK初始化前,需要对SDK的架构有所了解,具体如下图;可以看出SDK的代码结构是一个层次化分明的架构,这里对各层的作用和详细工作机制不阐述了,具体可以参见SDK的介绍文档。

   SDK代码的结构图

 

SDK根据上述架构,BCM模式启动的时候进行的初始化包括以下几个步骤:

1.           根据操作系统(linux、vxworks或unix等)不同调用sal_core_init()和sal_appl_init()两个函数的对应版本,分别对Core SAL和Appl SAL两部分进行初始化;

2.           linux系统下的sal_core_init()函数的主要工作时调用了函数

(1).sal_dpc_init()创建DPC(Deferred Procedure Call)的信号量和线程;(2).sal_appl_init()函数的linux版本则直接返回,没有做任何工作;

这两个函数虽然意义很大,但是值得我们研究的内容不多。

3.      然后调用sal_thread_create创建一个运行BCM模式的线程,并调用diag_shell()函数完成对BCM模式的数据进行初始化、命令行进行注册、设备探测和挂载、芯片初始化、客户命令注册、重启动和BCM模式退出等操作,主要通过调用diag_init()函数、sysconf_init()函数、diag_rc_set()函数、sysconf_probe()函数、sysconf_attach()函数、bcm_init()函数、custom_cmd()和sal_reboot()等函数实现,下面详细介绍下该函数的执行流程;

a.      diag_init()调用cmdlist_init()函数、init_symtab()函数、sal_srand()函数、gvar_init()函数和sh_bg_init()函数等来完成命令行注册、芯片的寄存器和表项软件数据内存分配、随机数种子获取、全局变量初始化和所有设备可执行任务的内存分配(最多10条)和记录等工作;

b.      sysconf_init()函数除了初始化管理接口的调式函数外还调用soc_cm_init()函数来完成SOC的配置的管理接口的初始化;

c.      sysconf_probe()函数调用bde_create()函数和sysconf_chip_override()函数完成探测已经挂载的设备并建立对应的配置管理项,包括为每个设备的分配id等工作;

d.      然后对每个unit调用sysconf_attach()函数来对soc_cm_device_init ()初始的管理接口的设备挂载一些中断处理函数,注册PCI读写函数等,用管理接口的结构体的指针函数成员形式保存,以便可以删除和添加这些处理函数,并调用soc_cm_device_init()函数通过在里面再调用soc_attach()函数来对每一个unit建立并初始化芯片的soc_control_t structure信息及对其访问的互斥体;soc_attach()函数调用soc_feature_init函数、soc_intr_disable()函、soc_cmic_uc_msg_start函数、soc_info_config()函数(这个函数下面会继续调用)、soc_dcb_unit_init()函数和soc_counter_verify()函数分别进行支持特性赋值、关闭中断、开启对设备的CMIC的UC信息、soc信息初始化、CPU收发包缓存DCB初始化和各种counter寄存器软件记录特定初始化,并对SOC_CONTROL(unit)和SOC_PERSIST(unit)两个保存芯片设备信息的结构体一些成员进行赋值;

e.      调用diag_rc_set()函数来设置对每个芯片初始化配置的脚本文件名称和热启动的初始化配置脚本名称,如果没有指定全部用默认的配置;然后解析脚本中的配置项,运用脚本进行配置初始化(包括MMU的配置);

f.       然后对每个芯片调用bcm_init()函数开始芯片的初始化工作,其首先调用bcm_attach()函数对BCM_CONTROL(unit)信息的部分成员进行赋值,包括设备类型、设备名称和unit号等;然后调用_bcm_api_xlate_port_init()函数建立lport和bcm port的映射关系;并调用芯片各功能模块的初始化函数(trident是bcm_esw_init ()函数)来对各模块进行初始化;

g.      然后调用custom_cmd()函数加载BCM模式下用户配置的命令加载进去;

h.      这样整个SDK就初始化完毕,BCM模式就会提示BCM>等来等待用户输入命令;然后进入一个死循环一直调用sh_process()函数解析用户配置的命令,然后调用对应的SDK接口下发到驱动;

i.        如果用户输入退出命令,会调用sh_exit函数来处理,包括可选的是否回收已经分配的资源等任务;

j.        如果用户输入重启的命令则调用sal_reboot()函数linux版本是通过exit(0)实现。

 

另外,SDK为上层的初始化提供了调用接口system_init()函数对BCM交换芯片进行初始化,这部分是咱们应该重点关注的部分,当然该接口在BCM模式下用init命令也是可以被调用到的。下面详细讲解下:

a.      首先调用soc_reset_init()函数,ESW????????芯片里这个函数调用soc_do_init()函数来完事情;soc_do_init()函数会根据是否是重启动设备进行的配置不一样;

(1)    如果是热启动的设备则先调用soc_dma_abort()关闭所有DMA并调用soc_linkscan_config()函数设置CMIC(CPU Management InterfaceController)查询端口link状态,如果设置项为空则表示关闭端口link状态扫描;然后如果是初始化soc有失败标记的话调用soc_dma_abort()函数、soc_counter_stop()函数、soc_mem_scan_stop函数、soc_i2c_detach()函数和soc_l2x_stop()函数(有些其他芯片还调用soc_cmic_uc_msg_stop函数等)分别禁止所有的中断、禁止计数行为、禁止内存扫描动作、释放I2C 驱动内存、结束L2X(应该是用于mac地址学习和老化对CPU进行中断通知)相关线程和停止等;

然后调用soc_info_config()函数来初始化芯片端口的各种信息,包括芯片型号、各种类型端口的位图、芯片称号、mod数目、端口数目、hg口的位置、堆叠口位置、CPU口队列数目、用于时间同步端口数目、端口最大支持速率、meter pools、入端口QOS支持的队列数目等信息,另外对trident芯片支持QOS三级调度,所以还会调用soc_trident_num_cosq_init()对各个端口支持的队列数做特殊初始化,最后调用soc_esw_dport_init()函数对User to physical port map的映射及对user port的逆映射;

总之soc_reset_init()函数偏重于对芯片信息、端口属性和QOS队列属性等初始化;然后调用soc_feature_init()函数和soc_dcb_unit_init()函数完成芯片特性支持添加和CPU收发包缓存DCB的初始化工作;

然后调用soc_dma_attach()函数和soc_dma_init()函数对中断进行重新初始化,然后对通过PCI设置CMIC_CONFIG使能高级的DMA模式,包括Scatter/gather, reload, andunaligned transfers(这里具体含义不太明白),然后开启一些中断;

然后是对MAC_CTRL寄存器读写配置一些MAC层的收发使能;然后是设置MAC表项、MPLS表项、vlan和egress vlan、 L3表项的一些hash冲突的级别,接着使能MAC地址学习和老化通知、重新获取L3转发表项的长度和表项大小信息即可完成整个热启动的过程;

(2)    在不是热启动的情况下,会首先调用调用soc_info_config()函数、soc_feature_init()函数和soc_dcb_unit_init()函数来完成信么MMU、芯片特性支持和DCB初始化工作;

然后调用soc_endian_config() 函数和soc_pci_burst_enable()函数来完成硬件大小端和支持PCI读写突发情形的使能;

然后是调用soc_reset()函数来完成对芯片的一些配置,包括端口的phy配置和mac配置(比如寄存器有XLPORT_XMAC_CONTROL),及还会调用相应芯片的soc_reset_bcm56840_a0()函数完成对CPU口和出入方向属性的一些配置,如CMIC_XGXS1_PLL_CONTROL_*、CMIC_MISC_CONTROL、CMIC_SOFT_RESET_REG、ING_CONFIG_2、EGR_CONFIG_2、ING_Q_BEGIN和EGR_Q_BEGIN等寄存器;然后和热启动一样,通过PCI设置CMIC_CONFIG使能高级的DMA模式,对MAC_CTRL寄存器读写配置一些MAC层的收发使能就退出了soc_do_init()函数;

b.      然后调用soc_misc_init()函数对芯片的初始化信息进行核实判断,最终根据函数指针调用芯片相应的函数,trident调用的则是_soc_trident_misc_init()函数;_soc_trident_misc_init()函数首先_soc_trident_ser_init()函数对IFP、EFP、VFP和UDF等tcam表项的表项大小、起始地址等信息进行软件获取并记录,然后调用_soc_trident_clear_all_memory函数对CPU_COS_MAP_ONLY、FP_GLOBAL_MASK_TCAM、FP_GM_FIELDS、FP_TCAM、FP_UDF_TCAM、L2_USER_ENTRY_ONLY、L3_DEFIP_128_ONLY、L3_DEFIP_ONLY、L3_TUNNEL、MY_STATION_TCAM_ENTRY_ONLY、VFP_TCAM、VLAN_SUBNET_ONLY、EFP_TCAM、FP_GLOBAL_MASK_TCAM_Xm、FP_GLOBAL_MASK_TCAM_Ym、L3_ECMP_XM、L3_ECMP_YM、EGR_IPMC_CFG2、EGR_VLAN_CONTROL_1、_XLPORT_MIB_RESET等表项进行清空;然后_soc_trident_misc_init()函数继续对CPU_PBM、CPU_PBM_2m、ISBS_PORT_TO_PIPE_MAPPINGm、EGR_ING_PORTm、XLPORT_CONFIGr、XLPORT_MODE_REG、IARB_MAIN_TDMm、EGR_PERQ_XMT_COUNTERS_BASE_ADDR、MISCCONFIG、ING_BYPASS_CTRL、EGR_BYPASS_CTRL、EGR_ENABLE、EPC_LINK_BMAP、ING_CONFIG_64、EGR_CONFIG_1、EGR_VLAN_CONTROL_1、ING_EN_EFILTER_BITMAP、SW2_FP_DST_ACTION_CONTROL、RTAG7_FLOW_BASED_HASH、RTAG7_HASH_ECMP、CMIC_I2C_STAT、CMIC_RATE_ADJUST_I2C、CMIC_RATE_ADJUST_INT_MDIO等寄存器或表项进行初始化赋值操作,并调用_trident_ledup_init对端口进行点灯操作,还调用_soc_trident_fcoe_config_init对芯片的FCOE功能进行初始化;

c.      然后调用soc_mmu_init()函数对MMU进行初始化,和soc_misc_init()函数一样,也是根据不同的芯片挂载不同的函数指针,这里会调用_soc_trident_mmu_init()函数对trident芯片的MMU进行初始化;包括GH、PG、SSP、SP、Port Min、PORT_MAX_SHARED_CELL、Queue Min等的划分,MMU port到phy port的映,及MCQ_CONFIG、OP_THR_CONFIG、OP_VOQ_PORT_CONFIG、OVQ_DROP_THRESHOLD0、OVQ_DROP_THRESHOLD_RESET_LIMIT、OVQ_FLOWCONTROL_THRESHOLD、OVQ_MCQ_CREDITS、MCQ_FIFO_BASE_REG、PORT_PAUSE_ENABLE0_64、INPUT_PORT_RX_ENABLE0_64、S3_CONFIG、S2_CONFIG、S2_S3_ROUTING等voq和Qos相关功能的MMU相关寄存器初始化;

d.      然后调用soc_l2x_start函数开启对MAC地址学习和老化的信息通知功能,主要是创建一个线程;

e.      然后调用bcm_init()函数对芯片进一步初始化,实际对trident芯片调用的是bcm_esw_init()函数,该函数再调用_bcm_esw_init()函数,该函数主要的是分别调用bcm_esw_linkscan_enable_set()函数、_bcm_modules_init()函数和bcm_esw_rcpu_init()函数,来实现关闭端口状态扫描、初始化芯片各个模块、初始化RCPU机制的主控模块:然后_bcm_esw_init()函数调用_bcm_esw_switch_init()函数来实现对CPU队列的初始化和对芯片的一些特殊控制信息,主要是通过调用bcm_esw_switch_rcpu_encap_priority_map_set()函数和bcm_esw_switch_control_set()函数来设置的。其中的_bcm_modules_init()函数调用芯片转发流程的各个模块的初始化函数,具体如下图:

        

 

此处内容较多但是非常重要,希望感兴趣的同学能查看对应代码实际学习下相关内容,只提一点,bcm_esw_l2_init函数会调用_bcm_l2_bpdu_init函数对l2_user_etry表项设置BPDU报文上CPU的规则;

f.       然后对unit的每个端口调用bcm_port_stp_set()函数、bcm_port_autoneg_set()函数和bcm_stat_clear()函数分别设置端口的STP的状态为转发、是否自动协商和清楚端口统计;

g.      然后调用bcm_linkscan_enable_set函数来定期查询端口的link状态;

h.      部分芯片还会调用bcm_linkscan_register注册trunk口的link状态查询回调函数;

 

 

SDK各个模块之间的关系:

Broadcom提供的sdk软件包包括了broadcom公司的交换芯片、phy芯片、cpu等芯片的驱动程序、器件操作接口、应用层接口;如下图所示:

 


对于bcm的交换芯片sdk包,主要模块有:

用户应用程序:用户自由定制的应用系统,通过sdk提供的接口控制芯片。

BCMX API:为用户应用程序提供的通用接口,不区分芯片,以芯片提供的业务功能为粒度。

BCM API: 驱动级接口,提供芯片各种读写控制接口,可以由用户应用程序调用,设置特定、读取寄存器,或查询芯片信息;

   BCMX API是对BCM API进行了下封装,一般的应用直接使用BCM API就可以;

 

BCM SDK支持的芯片比较多,使用时需要确定自己用的芯片是哪个系列的,BCM API接口函数在dispath中使用下面方式对应到芯片的类型的操作入口,

#defineBCM_DLIST_ENTRY(_dtype)\

bcm_##_dtype##_auth_mac_add,

static int(*_auth_mac_add_dispatch[])(

    int unit,

    int port,

    bcm_mac_t mac) =

{

#include<bcm_int/bcm_dlist.h>

0

};

##_dtype##:##_dtype##为芯片系列类型,如robo系列_dtype==robo;

 

芯片功能使用比较简单可靠的方式是参考\src\appl\diag\cmdlist.c,在sdk\include\soc\defs.h定义了对某些命令功能的支持。文件中对应芯片类型的命令处理列表,里面有芯片功能相关的命令行说明及处理。

 

   Sdk如果不进行裁剪进行编译时默认支持所有芯片,在sdk目录下的make子目录中的make文件进行设置,可以过滤掉不关心的器件。

   在系统启动初始化过程中通过调用sdk的初始化接口,完成交换芯片的初始化操作,系统初始化完成后,通过用户应用程序调用BCMX api或者BCM api接口进行业务的控制操作。

 

命令定义,添加在:Cmdlist.c

芯片支持宏定义:defs.h

Insmod 入口在,gmodule.c

 

内核学习调试宏:gmodule.h

/************add by renxl****************/

//#define __KDEBUG__  

#ifdef __KDEBUG__ 

#define REN_KDEBUG(level, format, ...)  printk("[%s|%5d|%s] "format,level,__LINE__, __func__,##__VA_ARGS__ )

#else 

#define REN_KDEBUG(format,...) 

#endif

用户态调试学习宏开关:

/************add by renxl****************/

#define __DEBUG__  

#ifdef __DEBUG__ 

#define REN_DEBUG(level, format, ...)  printf("[%s|%5d|%s] "format,level,__LINE__, __func__,##__VA_ARGS__ )

#else 

#define REN_DEBUG(format,...) 

#endif

函数执行流程:

用户接口:bcm.user.proxy  入口bcm-diag-proxy.c:main.o 726,

文件关联:bcm-diag-proxy.c çè/usr/share/linux-uk-proxy.c

默认无参数调用:

1.      _kernel_fd_attach(intinput_fd, int output_fd) 583 :打开内核设备接口,通知内核创建服务,函数指针赋值。

a.调用:linux_uk_proxy_open()589,->源文件usr/share/linux-uk-proxy.c:58行,打开内核模块linux-uk-proxy.ko(设备号125)的设备接口:linux-uk-proxy(主设备号125,次设备号0,用命令:mknod /dev/linux-uk-proxy c 125 0) 在在文件内部记录文件号:staticint _dev_fd = -1;

b. linux_uk_proxy_service_create():602 –>源文件Linux-uk-proxy.c:84通知通过ioctl()和内核交互,创建输入输出内核服务线程。

c.     reader.ctrl.input_cb= (proxy_data_cb_t)_kernel_proxy_input_cb;

   reader.ctrl.output_cb = (proxy_data_cb_t)_fd_output_cb;

reader.ctrl.exit_cb= (proxy_data_cb_t)_kernel_proxy_input_exit_cb;

这些函数都在linux-uk-proxy.c中定义。

d. proxy_service_start(&reader.ctrl,1);启动线程:调用proxy-service.c里面的proxy_service_start(proxy_ctrl_t* ctrl, int fork),参数决定了创建分离线程或者是前台线程。

                   proxy_service_start(&reader.ctrl,1);分离线程

                   proxy_service_start(&writer.ctrl,0);前台线程:命令行就是在这里等待输入命令------

到此内核接口初始化完成------

3.            之后的所有交互都是基于kernel/modules/linux-uk-proxy.c

文件关联:usr/share/linux-uk-proxy.cçè/kernel/modules/linux-uk-proxy.c

模块linux-uk-proxy.ko函数结构体:

static gmodule_t_gmodule = {

    name: LUK_MODULE_NAME,

    major: LUK_DEVICE_MAJOR,

    init: _init,

    cleanup: _cleanup,

    pprint: _pprint,

    ioctl: _ioctl,

    open: NULL,

    close: NULL,

};

主要接口:用户接口 ========ioctl(int fd,unsigned int cmd, unsigned long arg)

                内核接口========_ioctl(unsigned int cmd, unsigned long arg)

         接口命令:linux-uk-proxy.h:

#define LUK_VERSION                  _IO(LUK_MAGIC,0)==版本查询

#define LUK_SERVICE_CREATE   _IO(LUK_MAGIC,1)==创建内核服务

#define LUK_SERVICE_DESTROY         _IO(LUK_MAGIC,2)==注销内核服务

#define LUK_SERVICE_RECV       _IO(LUK_MAGIC,3)==内核接收数据

#define LUK_SERVICE_SEND       _IO(LUK_MAGIC,4)==内核发送数据

#define LUK_SERVICE_SUSPEND         _IO(LUK_MAGIC,5)==挂起服务

#define LUK_SERVICE_RESUME _IO(LUK_MAGIC,6)==注册服务

4.            linux-bcm-diag-full.ko模块

当这个模块被插入到内核的时候,linux-bcm-diag-full模块的_init函数会执行(linux-bcm-diag-full.c=====416行)

         _init()函数调用module/uk-proxy/linux-uk-proxy.c里面的linux_uk_proxy_service_create()函数,创建内核proxy service.

         在调用sal_thread_create("bcm-shell",0, 0, _bcm_shell, 0);创建bcm-shell内核线程,处理接收到的命令

         _bcm_shell()在bcm-diag-full.c的280行,调用sal_core_init()?????初始化核心模块,

         Diag-shell()àsh_process(0, "BCM", TRUE);

5.            linux-user-bde.c 里面定义了使用linux驱动/dev/spi-dev1.0

SDK根据上述架构,BCM模式启动的时候进行的初始化包括以下几个步骤:

 

1.     根据操作系统(linux、vxworks或unix等)不同调用sal_core_init()和sal_appl_init()两个函数的对应版本,分别对Core SAL和Appl SAL两部分进行初始化;linux系统下的sal_core_init()函数的主要工作时调用了函数sal_dpc_init()创建DPC(Deferred Procedure Call)的信号量和线程;sal_appl_init()函数的linux版本则直接返回,没有做任何工作;这两个函数虽然意义很大,但是值得我们研究的内容不多。

 

2.     然后调用sal_thread_create创建一个运行BCM模式的线程,并调用diag_shell()函数完成对BCM模式的数据进行初始化、命令行进行注册、设备探测和挂载、芯片初始化、客户命令注册、重启动和BCM模式退出等操作,主要通过调用diag_init()函数、sysconf_init()函数、diag_rc_set()函数、sysconf_probe()函数、sysconf_attach()函数、bcm_init()函数、custom_cmd()和sal_reboot()等函数实现,下面详细介绍下该函数的执行流程;

 

a.     diag_init()调用cmdlist_init()函数、init_symtab()函数、sal_srand()函数、gvar_init()函数和sh_bg_init()函数等来完成命令行注册、芯片的寄存器和表项软件数据内存分配、随机数种子获取、全局变量初始化和所有设备可执行任务的内存分配(最多10条)和记录等工作;

 

b.     sysconf_init()函数除了初始化管理接口的调式函数外还调用soc_cm_init()函数来完成SOC的配置的管理接口的初始化;

 

c.     sysconf_probe()函数调用bde_create()函数和sysconf_chip_override()函数完成探测已经挂载的设备并建立对应的配置管理项,包括为每个设备的分配id等工作;

 

d.     然后对每个unit调用sysconf_attach()函数来对soc_cm_device_init ()初始的管理接口的设备挂载一些中断处理函数,注册PCI读写函数等,用管理接口的结构体的指针函数成员形式保存,以便可以删除和添加这些处理函数,并调用soc_cm_device_init()函数通过在里面再调用soc_attach()函数来对每一个unit建立并初始化芯片的soc_control_t structure信息及对其访问的互斥体;soc_attach()函数调用soc_feature_init函数、soc_intr_disable()函、soc_cmic_uc_msg_start函数、soc_info_config()函数(这个函数下面会继续调用)、soc_dcb_unit_init()函数和soc_counter_verify()函数分别进行支持特性赋值、关闭中断、开启对设备的CMIC的UC信息、soc信息初始化、CPU收发包缓存DCB初始化和各种counter寄存器软件记录特定初始化,并对SOC_CONTROL(unit)和SOC_PERSIST(unit)两个保存芯片设备信息的结构体一些成员进行赋值;

 

e.     调用diag_rc_set()函数来设置对每个芯片初始化配置的脚本文件名称和热启动的初始化配置脚本名称,如果没有指定全部用默认的配置;然后解析脚本中的配置项,运用脚本进行配置初始化(包括MMU的配置);

 

f.      然后对每个芯片调用bcm_init()函数开始芯片的初始化工作,其首先调用bcm_attach()函数对BCM_CONTROL(unit)信息的部分成员进行赋值,包括设备类型、设备名称和unit号等;然后调用_bcm_api_xlate_port_init()函数建立lport和bcm port的映射关系;并调用芯片各功能模块的初始化函数(trident是bcm_esw_init ()函数)来对各模块进行初始化;

 

g.     然后调用custom_cmd()函数加载BCM模式下用户配置的命令加载进去;

 

h.     这样整个SDK就初始化完毕,BCM模式就会提示BCM>等来等待用户输入命令;然后进入一个死循环一直调用sh_process()函数解析用户配置的命令,然后调用对应的SDK接口下发到驱动;

 

i.       如果用户输入退出命令,会调用sh_exit函数来处理,包括可选的是否回收已经分配的资源等任务;

 

j.       如果用户输入重启的命令则调用sal_reboot()函数linux版本是通过exit(0)实现。

 

 

 

另外,SDK为上层的初始化提供了调用接口system_init()函数对BCM交换芯片进行初始化,这部分是咱们应该重点关注的部分,当然该接口在BCM模式下用init命令也是可以被调用到的。下面详细讲解下:

 

a.     首先调用soc_reset_init()函数,ESW芯片里这个函数调用soc_do_init()函数来完事情;soc_do_init()函数会根据是否是重启动设备进行的配置不一样;

 

(1)   如果是热启动的设备则先调用soc_dma_abort()关闭所有DMA并调用soc_linkscan_config()函数设置CMIC(CPU Management InterfaceController)查询端口link状态,如果设置项为空则表示关闭端口link状态扫描;然后如果是初始化soc有失败标记的话调用soc_dma_abort()函数、soc_counter_stop()函数、soc_mem_scan_stop函数、soc_i2c_detach()函数和soc_l2x_stop()函数(有些其他芯片还调用soc_cmic_uc_msg_stop函数等)分别禁止所有的中断、禁止计数行为、禁止内存扫描动作、释放I2C 驱动内存、结束L2X(应该是用于mac地址学习和老化对CPU进行中断通知)相关线程和停止等;然后调用soc_info_config()函数来初始化芯片端口的各种信息,包括芯片型号、各种类型端口的位图、芯片称号、mod数目、端口数目、hg口的位置、堆叠口位置、CPU口队列数目、用于时间同步端口数目、端口最大支持速率、meter pools、入端口QOS支持的队列数目等信息,另外对trident芯片支持QOS三级调度,所以还会调用soc_trident_num_cosq_init()对各个端口支持的队列数做特殊初始化,最后调用soc_esw_dport_init()函数对User to physical port map的映射及对user port的逆映射;总之soc_reset_init()函数偏重于对芯片信息、端口属性和QOS队列属性等初始化;然后调用soc_feature_init()函数和soc_dcb_unit_init()函数完成芯片特性支持添加和CPU收发包缓存DCB的初始化工作;然后调用soc_dma_attach()函数和soc_dma_init()函数对中断进行重新初始化,然后对通过PCI设置CMIC_CONFIG使能高级的DMA模式,包括Scatter/gather, reload, andunaligned transfers(这里具体含义不太明白),然后开启一些中断;然后是对MAC_CTRL寄存器读写配置一些MAC层的收发使能;然后是设置MAC表项、MPLS表项、vlan和egress vlan、 L3表项的一些hash冲突的级别,接着使能MAC地址学习和老化通知、重新获取L3转发表项的长度和表项大小信息即可完成整个热启动的过程;

 

(2)   在不是热启动的情况下,会首先调用调用soc_info_config()函数、soc_feature_init()函数和soc_dcb_unit_init()函数来完成信么MMU、芯片特性支持和DCB初始化工作;然后调用soc_endian_config() 函数和soc_pci_burst_enable()函数来完成硬件大小端和支持PCI读写突发情形的使能;然后是调用soc_reset()函数来完成对芯片的一些配置,包括端口的phy配置和mac配置(比如寄存器有XLPORT_XMAC_CONTROL),及还会调用相应芯片的soc_reset_bcm56840_a0()函数完成对CPU口和出入方向属性的一些配置,如CMIC_XGXS1_PLL_CONTROL_*、CMIC_MISC_CONTROL、CMIC_SOFT_RESET_REG、ING_CONFIG_2、EGR_CONFIG_2、ING_Q_BEGIN和EGR_Q_BEGIN等寄存器;然后和热启动一样,通过PCI设置CMIC_CONFIG使能高级的DMA模式,对MAC_CTRL寄存器读写配置一些MAC层的收发使能就退出了soc_do_init()函数;

 

b.     然后调用soc_misc_init()函数对芯片的初始化信息进行核实判断,最终根据函数指针调用芯片相应的函数,trident调用的则是_soc_trident_misc_init()函数;_soc_trident_misc_init()函数首先_soc_trident_ser_init()函数对IFP、EFP、VFP和UDF等tcam表项的表项大小、起始地址等信息进行软件获取并记录,然后调用_soc_trident_clear_all_memory函数对CPU_COS_MAP_ONLY、FP_GLOBAL_MASK_TCAM、FP_GM_FIELDS、FP_TCAM、FP_UDF_TCAM、L2_USER_ENTRY_ONLY、L3_DEFIP_128_ONLY、L3_DEFIP_ONLY、L3_TUNNEL、MY_STATION_TCAM_ENTRY_ONLY、VFP_TCAM、VLAN_SUBNET_ONLY、EFP_TCAM、FP_GLOBAL_MASK_TCAM_Xm、FP_GLOBAL_MASK_TCAM_Ym、L3_ECMP_XM、L3_ECMP_YM、EGR_IPMC_CFG2、EGR_VLAN_CONTROL_1、_XLPORT_MIB_RESET等表项进行清空;然后_soc_trident_misc_init()函数继续对CPU_PBM、CPU_PBM_2m、ISBS_PORT_TO_PIPE_MAPPINGm、EGR_ING_PORTm、XLPORT_CONFIGr、XLPORT_MODE_REG、IARB_MAIN_TDMm、EGR_PERQ_XMT_COUNTERS_BASE_ADDR、MISCCONFIG、ING_BYPASS_CTRL、EGR_BYPASS_CTRL、EGR_ENABLE、EPC_LINK_BMAP、ING_CONFIG_64、EGR_CONFIG_1、EGR_VLAN_CONTROL_1、ING_EN_EFILTER_BITMAP、SW2_FP_DST_ACTION_CONTROL、RTAG7_FLOW_BASED_HASH、RTAG7_HASH_ECMP、CMIC_I2C_STAT、CMIC_RATE_ADJUST_I2C、CMIC_RATE_ADJUST_INT_MDIO等寄存器或表项进行初始化赋值操作,并调用_trident_ledup_init对端口进行点灯操作,还调用_soc_trident_fcoe_config_init对芯片的FCOE功能进行初始化;

 

c.     然后调用soc_mmu_init()函数对MMU进行初始化,和soc_misc_init()函数一样,也是根据不同的芯片挂载不同的函数指针,这里会调用_soc_trident_mmu_init()函数对trident芯片的MMU进行初始化;包括GH、PG、SSP、SP、Port Min、PORT_MAX_SHARED_CELL、Queue Min等的划分,MMU port到phy port的映,及MCQ_CONFIG、OP_THR_CONFIG、OP_VOQ_PORT_CONFIG、OVQ_DROP_THRESHOLD0、OVQ_DROP_THRESHOLD_RESET_LIMIT、OVQ_FLOWCONTROL_THRESHOLD、OVQ_MCQ_CREDITS、MCQ_FIFO_BASE_REG、PORT_PAUSE_ENABLE0_64、INPUT_PORT_RX_ENABLE0_64、S3_CONFIG、S2_CONFIG、S2_S3_ROUTING等voq和Qos相关功能的MMU相关寄存器初始化;

 

d.     然后调用soc_l2x_start函数开启对MAC地址学习和老化的信息通知功能,主要是创建一个线程;

 

e.     然后调用bcm_init()函数对芯片进一步初始化,实际对trident芯片调用的是bcm_esw_init()函数,该函数再调用_bcm_esw_init()函数,该函数主要的是分别调用bcm_esw_linkscan_enable_set()函数、_bcm_modules_init()函数和bcm_esw_rcpu_init()函数,来实现关闭端口状态扫描、初始化芯片各个模块、初始化RCPU机制的主控模块:然后_bcm_esw_init()函数调用_bcm_esw_switch_init()函数来实现对CPU队列的初始化和对芯片的一些特殊控制信息,主要是通过调用bcm_esw_switch_rcpu_encap_priority_map_set()函数和bcm_esw_switch_control_set()函数来设置的。其中的_bcm_modules_init()函数调用芯片转发流程的各个模块的初始化函数,具体如下图:

1 0