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.

[参考译文] TMS320C6678:QMSS 存储器区域和主机解码器地址

Guru**** 2564390 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/596221/tms320c6678-qmss-memory-region-and-host-decriptor-address

器件型号:TMS320C6678

大家好。
我使用 c6678.有关 QMSS 存储器区域和主机描述符的问题。
我的配置是使用累加器列表内部链接 RAM 和高优先级队列。 如果我理解得当、主机描述符基址必须是全局的。 但是 QMSS 能够将描述符从高优先级队列移动到每个内核的本地存储器中。 从累加器列表中获取的 ISR 内容,每个内核的描述符地址0x108nnnnn。 这意味着从 core0 L2读取所有内核?
如何配置以获取具有本地地址的主机描述符?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!

    我们将对此进行研究。 反馈将发布在此处。

    此致、
    Yordan
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!

    您能否详细说明您用于此测试的处理器软件和示例?

    此致、Eric
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、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。