大家好。
我使用 c6678.有关 QMSS 存储器区域和主机描述符的问题。
我的配置是使用累加器列表内部链接 RAM 和高优先级队列。 如果我理解得当、主机描述符基址必须是全局的。 但是 QMSS 能够将描述符从高优先级队列移动到每个内核的本地存储器中。 从累加器列表中获取的 ISR 内容,每个内核的描述符地址0x108nnnnn。 这意味着从 core0 L2读取所有内核?
如何配置以获取具有本地地址的主机描述符?
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
大家好。
我使用 c6678.有关 QMSS 存储器区域和主机描述符的问题。
我的配置是使用累加器列表内部链接 RAM 和高优先级队列。 如果我理解得当、主机描述符基址必须是全局的。 但是 QMSS 能够将描述符从高优先级队列移动到每个内核的本地存储器中。 从累加器列表中获取的 ISR 内容,每个内核的描述符地址0x108nnnnn。 这意味着从 core0 L2读取所有内核?
如何配置以获取具有本地地址的主机描述符?
您好、Eric。
我的代码基于 pdk_C6678_1_1_2_6中的/pa/drv/multicore 示例。
我的初始化过程:
//仅适用于内核0
#define internal_linking_RAM 1.
Int32 Init_Qmss (空)
{
int32结果;
Qms_MemRegInfo memCfg;
Qmss_InitCfg qmsInitConfig;
cpi_DescCfg cpiDescCfg;
uint32 numAllocated;
/*初始化 QMSS */
memset (&qmsInitConfig、0、sizeof (Qms_InitCfg));
/*设置 QMSS 配置*/
#if internal_linking_RAM
/*使用内部链接 RAM */
qmsInitConfig.linkingRAM0Base = 0;
qmsInitConfig.linkingRAM0Size = 0;
qmsInitConfig.linkingRAM1Base = 0x0;
qmsInitConfig.maxDescNum = NUM_HOST_DESC;
其他
memset ((void *)链接 RAM0、0、sizeof (链接 RAM0))(&L);
/*使用外部链接 RAM */
qmsInitConfig.linkingRAM0Base = Convert_CoreLocal2GlobalAddr ((uint32) linkingRAM0);
qmsInitConfig.linkingRAM0Size = NUM_HOST_DESC;
qmsInitConfig.linkingRAM1Base = 0x0;
qmsInitConfig.maxDescNum = NUM_HOST_DESC;
#endif
qmsInitConfig.pdspFirmware[0].pdspId = Qmss_PdspId_PDSP1;
#ifdef _lif_ENDIAN
qmssInitConfig.pdspFirmware[0].firmware =(void *)&acc48_le;
qmssInitConfig.pdspFirmware[0].size = sizeof (acc48_le);
其他
qmssInitConfig.pdspFirmware[0].firmware =(void *)&acc48_BY;
qmssInitConfig.pdspFirmware[0].size = sizeof (acc48_BE);
#endif
/*初始化队列管理器*/
结果= Qmss_init (&qmsInitConfig、&qmsGblCfgParams);
if (结果!= QMSS_SOK)
{
IFSYSPRINT (System_printf ("初始化队列管理器子系统时出错,错误代码:%d\n",结果);
DEBUG_LOOP (1);
}
/*在此内核上启动队列管理器*/
Qmss_start ();
/*设置描述符内存区域。
*
*描述符基址必须是全局地址和
*所有存储器区域都必须按的升序设置
*描述符基址。
*
/*需要初始化和设置 CPSW 主机描述符*/
memset (gHostDesc、0、size_host_Desc * NUM_HOST_DESC);
memCfg.descBase = Convert_CoreLocal2GlobalAddr ((uint32) gHostDesc);//(uint32 *) gHostDesc;
memCfg.descSize = size_host_Desc;
memCfg.descNum = NUM_HOST_DESC;
memCfg.managDescFlag = Qms_ManagementDesc_manage_descriptor;
memCfg.memRegion = Qms_MemRegion_memory_REGION0;
memCfg.startIndex = 0;
/*插入主机描述符内存区域*/
结果= Qms_insertMemoryRegion (&memCfg);
如果(结果= QMSS_MEMREGION_END_INITILIZED)
{
IFSYSPRINT (System_printf ("内存区域%d 已初始化\n"、memCfg.memRegion);
}
否则、如果(结果< QMSS_SOK)
{
IFSYSPRINT (System_printf ("错误:插入内存区域%d、错误代码:%d\n"、memCfg.memRegion、结果);
DEBUG_LOOP (1);
}
/*初始化我们刚刚在上分配的所有描述符
以上*内存区域。 使用一些良好的描述符设置描述符
*在我们使用它们进行数据传输之前已知的值。
*
memset (&cppiDescCfg、0、sizeof (cppiDescCfg));
cppiDesccfg.memRegion = Qms_MemRegion_memory_REGION0;
cppiDescCfg.descNum = NUM_HOST_DESC;
cppiDescCfg.destQueueNum = QMSS_PARAM_NOT _指定;
cpiDesccfg.queueType = Qms_QueueType_General_Purpose;
cppiDescCfg.initDesc = Cppi_InitDesc_init_descriptor;
cppiDescCfg.descType = Cppi_DescType_host;
默认情况下为/*:
*(1)将描述符返回到队列末尾
*(2)始终将整个数据包返回到此空闲队列
*(3)设置在 SOP 缓冲区的开头始终存在 PS 数据
*(4)配置自由 q num < 4K、因此 qMgr = 0
*(5)默认情况下回收到相同的空闲队列。
*
cppidDesccfg.PushreturnPolicy = Qmss_Location_tail;
cppiDesccfg.host.returnPolicy = Cppi_ReturnPolicy_return_entural_packet;
cpiDesccfg.host.psLocation = Cppi_PSLoc_PS_in_Desc;
cppiDesccfg.returnQueue.qMgr = 0;
cpiDesccfg.returnQueue.qNum = QMS_PARAM_NOT 指定;
cppiDesccfg.epibPresent = Cppi_EPIB_EPIB_Present;
/*初始化描述符、创建空闲队列并将描述符推送到全局空闲队列*/
if ((gGlobalFreeQHnd = Cppi_initDescriptor (&cppiDescCfg、&numAllocated))<= 0)
{
IFSYSPRINT (System_printf ("错误初始化自由描述符、错误:%d \n"、gGlobalFreeQHnd);
DEBUG_LOOP (1);
}
其他
{
IFSYSPRINT (System_printf ("初始化自由描述符。 \n");
}
/*队列管理器初始化完成*/
返回0;
}
init_cppi ();//与 TI 示例类似
//适用于所有内核
Int32 Setup_Rx (空)
{
int32结果、vectId;
uint8 isAllocated、accChannelNum、i;
uint16 numAccEntry、intThreshold;
Qmss_Queue rxFreeQInfo、rxQInfo;
ptr pcpipDesc;
Qmss_AccCmdCfg accCfg;
Cppi_RxFlowCfg rxFlowCfg;
Int16 EventID;
ptr pDataBuffer;
uint32 mySWInfo[]={0x11112222、0x334444};
Int32 coreToQueueSelector [NUM_Core];
易失性 uint32 coreNum;
/*获取内核编号。 *
coreNum = CSL_chipReadReg (CSL_CHIP_DNUM);
/*这是将内核映射到特定接收队列的表。 *
coreToQueueSelector [coreNum]= QMSS_HIGH_PRIORY_Queue_base + coreNum;
/*打开接收(Rx)队列。
*
*此队列将用于保存 pass/CPSW 接收的所有数据包
*
*为 rx 打开下一个可用的高优先级累加队列。*/
if (((gRxQHnd[coreNum]= Qmss_queueOpen (Qmss_QueueType_HIGH_PRIORY_queue、coreToQueueSelector [coreNum]、isAllocated))< 0)
{
IFSYSPRINT (System_printf ("打开 gRxQHnd 队列时出错\n");
DEBUG_LOOP (1);
}
rxQInfo = Qms_getQueueNumber (gRxQHnd[coreNum]);
/*累加器配置。 *
/*在 Rx 队列上设置高优先级累积中断。
*
*让我们使用以下设置配置累加器:
*(1)中断起搏被禁用。
*(2)每个接收到的数据包上的中断
*
intThreshold = RX_INT_THRESHOLD;
numAccEntry =(intThreshold + 1)* 2;
accChannelNum = coreNum;//pa_acc_channel_NUM;
/*初始化累加器列表内存*/
memset ((void *)&gHiPriAccumList、0、numAccEntry * 4);
/*确保我们正在编程的累加器通道不是
*当前正在使用。
*
结果= Qmss_disable累 加器(Qms_PdspId_PDSP1、accChannelNum);
if (结果!= QMSS_ACC_SOK &&结果!= QMSS_ACC_CHANNEL_NOT ACTIVE)
{
IFSYSPRINT (System_printf ("禁用通道的高优先级累加器时出错:%d 错误代码:%d\n"、
accChannelNum、结果));
DEBUG_LOOP (1);
}
/*设置累加器设置*/
accCfg.channel = accChannelNum;
accCfg.command = Qms_AccCmd_enable_channel;
accCfg.queueEnMask = 0;
accCfg.listAddress = Convert_CoreLocal2GlobalAddr ((uint32)&gHiAccumList);
accCfg.queMgrIndex = gRxQHnd[coreNum];
accCfg.maxPageEntry =(intThreshold + 1);//添加一个额外的条目来保持条目计数*/
accCfg.timerLoadCount = 40;
accCfg.interruptPacingMode = Qms_AccPacingMode_Last_interrupt;
accCfg.listEntrySize = Qms_AccEntrySize_REG_D;
accCfg.listCountMode = Qms_AccCountMode_entry_count;
accCfg.multiQueueMode = Qms_AccQueueMode_Single_queue;
/*对累加器进行编程*/
if ((结果= Qms_program累 加器(Qms_PdspId_PDSP1、&accCfg))!= QMSS_ACC_SOK)
{
IFSYSPRINT (System_printf ("为通道编程高优先级累加器时出错:%d 队列:%d 错误代码:%d\n",
accCfg.channel、accCfg.queMgrIndex、结果);
DEBUG_LOOP (1);
}
/*为与对应的系统事件注册中断
*我们正在使用的累加器通道。
*
Hwi_disable();
/*系统事件48 -累加器通道0-7 */
EventID = platform_ETH_EventID;
/*选择一个中断向量 ID 以使用*/
vectId = platform_ETH_interrupt;
/*为此事件注册我们的 ISR 句柄*/
//EventCombiner_dispatchPlug (EventID、(EventCombiner_FuncPtr) Cpsw_RxISR、(UArg)NULL、true);
EventCombiner_enableEvent (EventID);
/*将组合器的输出事件 ID (evevertId/32)映射到硬件中断7。 *
Hwi_EventMap (vectId、EventID >> 5);
/*启用中断7。 *
Hwi_enableInterrupt (vectId);
Hwi_enable();
/*内核之间共享以下 RX 队列,因此它们是共享的
初始化仅由内核0完成*/
if (!coreNum)
{
/*打开 Rx 自由描述符队列(Rx FDQ)。
*
*此队列将容纳所有 Rx 自由解码器。 这些描述符将是
*由传递 CPDMA 用于保存通过 CPSW 接收的数据。
*
if (((gRxFreeQHnd = Qmss_queueOpen (Qms_QueueType_Hungaring_counter_queue、QMSS_Hungaling_counter_Queue_base + NUM_cores/* QParam_MSS_not _specified*、&isAllocated))< 0)
{
IFSYSPRINT (System_printf ("打开 Rx 空闲描述符队列时出错");
DEBUG_LOOP (1);
}
SYS_Cache_WB (((void *)&gRxFreeQHnd、128、cache_wait);
}//LL
rxFreeQInfo = Qms_getQueueNumber (gRxFreeQHnd);
//将一些空闲描述符附加到刚刚打开的 Rx 空闲队列。 *
对于(I = 0;I < NUM_RX_DESC;I++)
{
/*从我们设置的全局空闲队列中获取一个空闲描述符
*在初始化期间。
*
if ((pCpipiDESC = Qms_queuePop (gGlobalFreeQHnd))= NULL)
{
IFSYSPRINT (System_printf ("错误的提升描述符。\n"\});
中断;
}
/*从硬件返回的描述符地址具有
*在最后4位中附加到地址的描述符大小。
*
*要获得真正的描述符大小,请始终屏蔽最后一个
*地址的4位。
*
pcpipDesc =(ptr)((uint32) pcpipDesc & 0xFFFFFFF0);
//pDataBuffer =(uint8 *)(&cppiMemRX[coreNum][i]);
//pDataBuffer =(ptr)((((uint32) st_rx_packet_buffer.rx_packet_buffer[coreNum][i])/*+ rtp_header_ALIGNEMNT*);
#if zero_copy
pDataBuffer =(ptr)((((uint32) rx_packet_buffer[coreNum][i])+ rtp_header_ALIGNEMNT);
其他
pDataBuffer =(ptr)((((uint32) rx_packet_buffer[coreNum][i]));
#endif
/*使用我们刚刚分配的缓冲区填充 Rx 自由描述符。 *
Cppi_setData (Cppi_DescType_host、pCpPiDesc、(UINT8 *) pDataBuffer、RX_BUF_SIZE);
/*保存原始缓冲区信息*/
cpi_setOriginalBufInfo (Cppi_DescType_host、pcpiDesc、(uint8 *) pDataBuffer、RX_BUF_SIZE);
/*设置完成队列:
*
*设置此 desc 的返回策略以返回到刚才的免费 q
*设置、而不是全局空闲队列。
*
Cppi_setReturnQueue (Cppi_DescType_host、pCpPiDesc、rxFreeQInfo);
cpi_setSoftwareInfo (Cppi_DescType_host、pCpipiDesc、(UINT8 *) mySWInfo);
Cppi_setPacketLen (Cppi_DescType_host、pCpipiDesc、RX_BUF_SIZE);
SYS_Cache_WB (pcpiDesc、size_host_Desc、cache_fence_wait);
/*将描述符推送到 Rx 空闲队列*/
Qmss_queuePushDescSize (gRxFreeQHnd、pCpiDesc、size_host_Desc);
}
if (i!= NUM_RX_DESC)
{
IFSYSPRINT (System_printf ("分配 Rx 自由描述符时出错\n");
DEBUG_LOOP (1);
}
//}
/*在每个内核上设置 Rx 流。 内核之间的唯一区别是 rxQInfo。
*
* Rx 流封装 CPDMA 将会封装的所有相关数据属性
*必须知道才能成功接收数据。
*
/*初始化流配置*/
memset (&rxFlowCfg、0、sizeof (Cppi_RxFlowCfg));
rxFreeQInfo = Qms_getQueueNumber (gRxFreeQHnd);
/*让 CPPI 选择下一个可用流程*/
rxFlowCfg.flowIdNum = CPPI_PARAM_NOT 指定;
rxFlowCfg.rx_dest_qmgr = rxQInfo.qMgr;
rxFlowCfg.rx_dest_qnum = rxQInfo.qNum;
rxFlowCfg.rx_desc_type = Cppi_DescType_host;
rxFlowCfg.rx_ps_location = Cppi_PSLoc_PS_in_Desc;
rxFlowCfg.rx_psinfo_present = 0;/*1 -启用 PS 信息[LL]*/
rxFlowCfg.rx_error_handling = 0;//丢弃数据包,默认情况下不会在饥饿时重试*/
rxFlowCfg.rx_einfo_present = 1;/* EPIB 信息存在*/
rxFlowCfg.rx_dest_tag_lo_SEL = 0;//禁用标记
rxFlowCfg.rx_dest_tag_hi_SEL = 0;
rxFlowCfg.rx_src_tag_lo_SEL = 0;
rxFlowCfg.rx_src_tag_hi_SEL = 0;
rxFlowCfg.rx_size_thresh_en = 0;//默认情况下,我们禁用 Rx 阈值*
rxFlowCfg.rx_size_thresh1_en = 0;//默认情况下,我们禁用 Rx 阈值*
rxFlowCfg.rx_size_thresh2_en = 0;//默认情况下,我们禁用 Rx 阈值*/
rxFlowCfg.rx_size_thresh0 = 0x0;
rxFlowCfg.rx_size_thresh1 = 0x0;
rxFlowCfg.rx_size_thresh2 = 0x0;
rxFlowCfg.rx_fdq0_sz0_qmgr = rxFreeQInfo.qMgr;//设置流的接收空闲队列*/
rxFlowCfg.rx_fdq0_sz0_qnum = rxFreeQInfo.qNum;
rxFlowCfg.rx_fdq0_sz1_qnum = 0x0;
rxFlowCfg.rx_fdq0_sz1_qmgr = 0x0;
rxFlowCfg.rx_fdq0_sz2_qnum = 0x0;
rxFlowCfg.rx_fdq0_sz2_qmgr = 0x0;
rxFlowCfg.rx_fdq0_sz3_qnum = 0x0;
rxFlowCfg.rx_fdq0_sz3_qmgr = 0x0;
rxFlowCfg.rx_fdq1_qnum = rxFreeQInfo.qNum;//使用 Rx Queue 选择描述符*/
rxFlowCfg.rx_fdq1_qmgr = rxFreeQInfo.qMgr;
rxFlowCfg.rx_fdq2_qnum = rxFreeQInfo.qNum;//使用 Rx Queue 选择描述符*/
rxFlowCfg.rx_fdq2_qmgr = rxFreeQInfo.qMgr;
rxFlowCfg.rx_fdq3_qnum = rxFreeQInfo.qNum;//使用 Rx Queue 选择描述符*/
rxFlowCfg.rx_fdq3_qmgr = rxFreeQInfo.qMgr;
/*配置 Rx 流*/
if ((gRxFlowHnd = Cppi_configureRxFlow (gCpdmaHnd、&rxFlowCfg、&isAllocated))= NULL)
{
IFSYSPRINT (System_printf ("配置 Rx 流时出错\n");
DEBUG_LOOP (1);
}
/*全部通过 Rx 配置完成。 返回成功。 *
返回0;
}
init_qmss_local (); // 与 TI 示例类似
谢谢、
Leon。