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:PCIe PHY 环回模式

Guru**** 2560390 points


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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/596704/tms320c6678-pcie-phy-loopback-mode

器件型号:TMS320C6678

您好!

我修改了 PCIe 示例项目以将其设置为 PHY 回送模式。 我按照用户手册中列出的步骤操作、看起来一切正常、但我看到了一些奇怪的行为。

从 RC 发送数据后、我查询 DEV_STAT_CTRL 寄存器中的致命、非致命、可纠正、不受支持的请求错误位。 不支持的请求错误位总是返回为1、同时返回非致命错误位。 但是、目标缓冲区与源缓冲区匹配、我在控制台中看到"根复合体接收到的数据"消息。

是否有人想知道为什么这些位设置为1、但回路模式成功?

谢谢、

Viney

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

    我已将此内容转发给 PCI 专家。 他们的反馈应发布在此处。

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

    用于 C66x 的 Processor SDK RTOS PCIe 驱动程序不支持 PCIe PHY 环回、我想您为此修改了它。 PCIe 链路建立后、但在数据写入测试之前、您是否看到设置了这些错误位? 为了使数据测试通过、您需要对地址转换进行一些更改(0x9000_0000和0x7000_0000)、您是否执行了这些操作?

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

    尊敬的 Eric:

    没错、我修改了现有项目以支持 PHY 回送模式。

    我注意到、即使在发送数据之前、这些错误位也会被设置。 LTSM 值为预期的11、我在控制台上看到"Link is up"消息。

    我使 PCIe_OB_LO_ADDR_RC 和 PCIe_IB_LO_ADDR_RC 保持不变、以使其正常工作。 我发送的数据会正确回传到相应的缓冲区中、但我不知道为什么会设置这些错误位。

    谢谢、

    Viney

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

    您能否上传修改后的环回代码(我想它就在 pcie_sample.c 中)并告诉我它是哪个 MCSDK 还是 Processor SDK RTOS 版本、那么我可以尝试吗?

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

    我使用的是 Processor SDK RTOS 版本3.02.00.05。

    以下是 pce_sample.c 中的代码:

    void main (void)

    #ifdef _TMS320C6x
    TSCL = 1;
    #endif
    #if!defined (device_K2K)&&!defined (device_K2H)&&!defined (device_K2E)&&!defined (device_K2L)&&\
    !defined (SOC_K2K)&&!defined (SOC_K2H)&&!defined (SOC_K2L)&& defined (SOC_K2E)&&!defined (SOC_K2G)&&\
    !defined (SOC_AM572x)&&!defined (SOC_AM571x)
    uint16_t lock=0;
    #endif
    pcieRet_e 返回值;
    pcieIbTransCfg_t ibCfg;
    pcieBarcfg_t barCfg;
    PCIe_Handle 句柄=空;
    无效 *pcieBase;
    dstBuf_t *pciedstBufBase;
    uint32_t i;
    #ifdef PCIe_REV1_HW
    SemaphoreP_Handle SEM =空;
    #endif

    /*从缓存中获取远程缓冲区*/
    cache_writeback (((void *)&dstBuf、sizeof (dstBuf));
    /*解锁 kicker 一次,不要重新锁定,因为它不是多核安全*/
    #if!defined (SOC_AM572x)&&!defined (SOC_AM571x)
    CSL_BootCfgUnlockKicker();
    #endif

    EDMA
    EDMA3_DRV_Handle hEdma =空;
    hEdma = edmaInit (hEdma);
    如果(hEdma=NULL) PCIe_logPrintf ("错误:EDMA 句柄未初始化!\n");
    #endif

    #ifndef IO_console
    console_printf ("io_console not defined。 大多数输出将转至 UART\n");
    #endif

    //PCIe_logPrintf ("*********) \n");
    //PCIe_logPrintf ("* PCIe 测试开始 *\n");

    printf (" \n");
    printf ("* PCIe 测试开始 *\n");

    if (PcieModeGbl = PCIe_RC_MODE)
    //PCIe_logPrintf ("* RC 模式 *\n");
    printf ("* RC 模式 *\n");
    其他
    PCIe_logPrintf ("* EP 模式 *\n");

    //PCIe_logPrintf ("*********) \n\n");
    printf (" \n\n");

    //PCIe_logPrintf ("版本号:0x%08x;字符串%s\n\n"、(无符号) PCIe_getversion ()、PCIe_getVersionStr ());
    printf ("版本号:0x%08x;字符串%s\n\n"、(无符号) PCIe_getversion ()、PCIe_getVersionStr());

    /*将设备配置传递到 LLD */
    如果((RetVal = PCIe_init (&pcieInitCfg))!= PCIe_RET_OK)

    //PCIe_logPrintf ("LLD 设备配置失败\n"\n);
    printf ("LLD 设备配置失败\n"\n);
    退出(1);


    /*初始化应用程序缓冲区*/
    pcieInitAppBuf();

    /*为 PCIe 模块加电*/
    if ((RetVal = pciePowerCfg())!= PCIe_RET_OK){
    //PCIe_logPrintf ("PCIe 加电失败(%d)\n"、(int) RetVal);
    printf ("PCIe 加电失败(%d)\n"、(int) RetVal);
    退出(1);


    //PCIe_logPrintf ("PCIe 加电.\n"PCIe);
    printf ("PCIe 上电。\n"PCIe 上电);

    如果((RetVal = PCIe_open (0、handle))!= PCIe_RET_OK)

    //PCIe_logPrintf ("打开失败(%d)\n"、(int) RetVal);
    printf ("打开失败(%d)\n"、(int) RetVal);
    退出(1);


    /*配置 SERDES*/
    if ((RetVal = pcieSerdesCfg())!= PCIe_RET_OK){
    //PCIe_logPrintf ("PCIe 串行器/解串器配置失败(%d)\n"、(int) RetVal);
    printf ("PCIe Serdes 配置失败(%d)\n"、(int) RetVal);
    退出(1);


    /*设置 PCIe 模式*/
    if ((RetVal = PCIe_setInterfaceMode (Handle、PcieModeGbl))!= PCIe_RET_OK){
    //PCIe_logPrintf ("设置 PCIe 模式失败(%d)\n"、(int) RetVal);
    printf ("设置 PCIe 模式失败(%d)\n"、(int) RetVal);
    退出(1);


    /*等待 PCIe SERDES PLL 锁定*/
    #if!defined (device_K2K)&&!defined (device_K2H)&&!defined (device_K2E)&&!defined (device_K2L)&&\
    !defined (SOC_K2K)&&!defined (SOC_K2H)&&!defined (SOC_K2L)&& defined (SOC_K2E)&&!defined (SOC_K2G)&&\
    !defined (SOC_AM572x)&&!defined (SOC_AM571x)
    while (!lock)

    CSL_BootCfgGetPCIEPLLLock (&L);

    #endif /*!device_K2K &&!device_K2H &&!device_K2E &&!device_K2L &&!SOC_K2G &&!SOC_AM572x &&!SOC_AM571x *


    //PCIe_logPrintf ("PLL 已配置。\n");
    printf ("PLL 已配置。\n");

    if (PcieModeGbl = PCIe_RC_MODE)

    /*为根复合体配置应用程序寄存器*/
    如果((RetVal = pcieCfgRC (handle))!= PCIe_RET_OK)

    //PCIe_logPrintf ("在 RC 模式(%d)中配置 PCIe 失败\n"、(int) RetVal);
    printf ("在 RC 模式(%d)中配置 PCIe 失败"、(int) RetVal);
    退出(1);


    /*配置地址转换*/

    barCfg.location = PCIe_location_local;
    barCfg.mode = PCIe_RC_MODE;
    barCfg.base = PCIe_IB_LO_ADDR_RC;
    barCfg.prefetch = PCIe_bar_non_PREF;
    barCfg.type = PCIe_bar_TYPE32;
    barCfg.memSpace = PCIe_bar_MEM_MEM;
    barCfg.idx = PCIe_bar_IDX_RC;

    如果((RetVal = PCIe_cfgBar (handle、&barCfg))!= PCIe_RET_OK)

    //PCIe_logPrintf ("未能配置条(%d)\n"、(int) RetVal);
    printf ("无法配置条(%d)\n"、(int) RetVal);
    退出(1);



    ibcfg.ibBar = PCIe_bar_IDX_RC;/*上面配置的匹配栏*/
    ibcfg.ibStartAddrLo = PCIe_IB_LO_ADDR_RC;
    ibcfg.ibStartAddrHi = PCIe_IB_HI_ADDR_RC;
    // ibCfg.ibOffsetAddr =(uint32_t) pcieConvert_CoreLocal2GlobalAddr ((uint32_t) dstBuf.buf);
    ibCfg.ibOffsetAddr =(uint32_t)(dstBuf.buf);
    ibcfg.region = PCIe_IB_REGASE_RC;

    如果((RetVal = pcieIbTransCfg (handle、&ibCfg))!= PCIe_RET_OK)

    //PCIe_logPrintf ("无法配置入站转换(%d)\n"、(int) RetVal);
    printf ("无法配置入站转换(%d)\n"、(int) RetVal);
    退出(1);

    其他

    //PCIe_logPrintf ("已成功配置入站转换!\n");
    printf ("已成功配置入站转换!\n");


    //配置 OB_OFFSET_INDEXn 寄存器- n 指的是 OB 转换区域
    if ((RetVal = pcieObTransCfg (handle、PCIe_OB_LO_ADDR_RC、PCIe_OB_HI_ADDR_RC、PCIe_OB_REGAL_RC))!= PCIe_RET_OK)

    //PCIe_logPrintf ("无法配置出站地址转换(%d)\n"、(int) RetVal);
    printf ("无法配置出站地址转换(%d)\n"、(int) RetVal);
    退出(1);

    其他

    //PCIe_logPrintf ("已成功配置出站转换!\n");
    printf ("已成功配置出站转换!\n");




    其他

    /*为端点配置应用程序寄存器*/
    if ((RetVal = pcieCfgEP (handle))!= PCIe_RET_OK)

    //PCIe_logPrintf ("未能在 EP 模式(%d)中配置 PCIe \n"、(int) RetVal);
    printf ("未能在 EP 模式(%d)中配置 PCIe \n"、(int) RetVal);
    退出(1);


    /*配置地址转换*/

    barCfg.location = PCIe_location_local;
    barCfg.mode = PCIe_EP_MODE;
    barCfg.base = PCIe_IB_LO_ADDR_EP;
    barCfg.prefetch = PCIe_bar_non_PREF;
    barCfg.type = PCIe_bar_TYPE32;
    barCfg.memSpace = PCIe_bar_MEM_MEM;
    barCfg.idx = PCIe_bar_IDX_EP;

    如果((RetVal = PCIe_cfgBar (handle、&barCfg))!= PCIe_RET_OK)

    printf ("配置条失败!\n"\});
    退出(1);


    ibcfg.ibBar = PCIe_bar_IDX_EP;/*上面配置的匹配栏*/
    ibcfg.ibStartAddrLo = PCIe_IB_LO_ADDR_EP;
    ibcfg.ibStartAddrHi = PCIe_IB_HI_ADDR_EP;
    ibcfg.ibOffsetAddr =(uint32_t) pcieConvert_CoreLocal2GlobalAddr ((uint32_t) dstBuf.buf);//这是出站读取的目标地址(DDR/L2/MSMC)
    ibcfg.region = PCIe_IB_REGASE_EP;

    如果((RetVal = pcieIbTransCfg (handle、&ibCfg))!= PCIe_RET_OK)

    printf ("无法配置入站转换(%d)!\n"、(int) RetVal);
    退出(1);

    其他

    printf ("已成功配置入站转换!\n");


    if ((RetVal = pcieObTransCfg (handle、PCIe_OB_LO_ADDR_EP、PCIe_OB_HI_ADDR_EP、PCIe_OB_REGAL_EP))!= PCIe_RET_OK)

    printf ("无法配置出站地址转换(%d)!\n"、(int) RetVal);
    退出(1);

    其他

    printf ("已成功配置出站转换!\n");



    printf ("正在开始链路训练...\n");


    //VK 5/15/17
    /*
    对于 PHY 环回模式、配置 Serdes 配置寄存器、将发送和接收路径设置为环回模式。
    在串行器/解串器配置通道0中启用 TX 回送和 RX 回送
    寄存器(SERDES_CFG0[TX_环 回]=0x2和
    SERDES_CFG0[RX_LOOPEN]=0x3)。
    –在串行器/解串器配置通道0寄存器中禁用信号丢失检测
    (SERDES_CFG0[RX_LOS]=0)。
    *

    if ((RetVal = enableTxAndRxLoopback (handle))!= PCIe_RET_OK)

    printf ("无法启用 Tx 和 Rx 环回! (%d)\n"、(int) RetVal);
    退出(1);



    /*启用链接培训*/
    如果((RetVal = pcieLtssmCtrl (handle、true))!= PCIe_RET_OK)

    printf ("无法启用链接培训! (%d)\n"、(int) RetVal);
    退出(1);


    //VK 5/15/17
    /*对于 PHY 回送模式:
    我们需要跳过
    检测 LTSSM 中的状态并强制链接从 POLL_ACTIVE 状态开始。
    –在端口强制链路的 LNK_STATE 字段中设置0x2 (POLL_ACTIVE 状态)
    寄存器(PL_FORCE_LINK_STATE]=0x2)。
    –在 PL_FORCE_LINK 寄存器的 FORCE_LINK 字段中设置0x1以强制连接
    链接到由 LINK_STATE 字段指定的状态
    (PL_FORCE_LINK_FORCE_LINK]=0x1)。
    *


    if ((RetVal = skipDetectStateIntsm (handle))!= PCIe_RET_OK)

    printf ("在 LTSSM 中跳过检测状态失败! (%d)\n"、(int) RetVal);
    退出(1);




    /*等待链接启动*/
    pcieWaitLinkUp (Handle);//Step 9 in section 2.11.1.1

    printf ("链路已启动。\n"\});
    if ((RetVal = pcieCheckLinkParams (handle))!= PCIe_RET_OK)

    printf ("链路宽度/速度验证失败:%d\n"、RetVal);
    /*如果将此示例用作,则可以删除此 exit()
    *包含非 TI 卡的模板、支持更慢或更窄的连接
    *
    退出(1);


    if ((RetVal = PCIe_getMemSpaceRange (handle、&pcieBase、NULL))!= PCIe_RET_OK){
    printf ("getMemSpaceRange Failed (%d)\n"、(int) RetVal);
    退出(1);


    //VK 5/18/17 -读取 DEV_STAT_CTRL_REG
    Read_devStatCtrlReg (句柄);



    #ifdef PCIe_REV1_HW
    /*将 PCIe 基座调整为指向远程目标缓冲器*/
    pcieBase =(char *) pcieBase +
    PCIe_window_MEM_BASE +/*数据区域不从低地址开始*/
    ((((uint32_t)&dstBuf)& 0xxfff);/* dstBuf 需要在 addr tran 中进行4K 对齐*/
    #endif
    pciedstBufBase =(dstBuf_t *) pcieBase;

    if (PcieModeGbl = PCIe_RC_MODE)

    #ifdef PCIe_REV1_HW
    SEM =模板设置 MSIAndINTX (句柄);
    #endif
    /******** /
    /*将单个消息推送到 EP、然后验证它是否回送了*/
    /******** /

    /*从 RC 写入 EP
    *

    (i=0;<PCIE_BUFSIZE_APP; i++)

    pciedstBufBase->buf[i]= srcBuf[i];



    /*
    (i=0;<PCIE_BUFSIZE_APP; i++)

    *((volatile uint32_t *) pcieBase + I)= srcBuf[i];

    *((volatile uint32_t *) pcieBase + PCIe_BUFSIZE_APP)= PCIe_example_BUF_full;
    *

    /*标记缓冲区已满、以便 EP 可以处理它*/
    pciedstBufBase->buf[PCIe_BUFSIZE_APP]= PCIe_example_BUF_full;

    //注意高速缓存一致性:由于 pcieBase 位于中,因此不需要回写
    外设地址空间而不是物理内存*/

    /*发送到 EP 的数据。
    RC 等待环回完成、然后
    从 EP *接收数据


    操作

    unsigned int key;
    KEY =_disable_interrupts ();
    CSL_XMC_invalidatePrefetchBuffer();
    cache_invL1d (((void *) dstBuf.buf、pcie_example_DSTBUF_Bytes、cache_bind_wait);
    cache_invL2 (((void *) dstBuf.buf、PCIe_example_DSTBUF_Bytes、cache_bind_wait);

    /*重新启用中断。 *
    RESTORE_INTERRUPTS (KEY);

    //cache_invalidate (((void *) dstBuf.buf、PCIe_example_DSTBUF_Bytes);
    }while (dstBuf.buf[PCIe_BUFSIZE_APP]!= PCIe_Example_BUF_Full);


    /*检查所有数据*/
    (i=0;<PCIE_BUFSIZE_APP; i++)

    if (dstBuf.buf[i]!= srcBuf[i])

    printf ("接收到的数据=%u\n 转码数据=%u\n 索引=%u.\n\n 测试失败。\n"、
    (unsigned) dstBuf.buf[i]、(unsigned) srcBuf[i]、(unsigned) i);
    退出(1);



    printf ("根复合体接收到的数据。\n");
    #ifdef PCIe_REV1_HW
    pcieRcWaitInts (手柄、SEM、pcieBase);
    #endif



    #ifdef PCIe_example_dma_rc
    IF (PcieExampleEdmaRC (pciedstBufBase、0xbabeface、100000、
    (EDMA3_DRV_Handle) hEdma
    )){
    printf ("传递令牌失败\n");
    退出(1);


    printf ("根复合体 DMA 接收到的数据。\n");
    printf ("EDMA 测试通过。\n"\});
    printf ("\n==使用 DMA 传输的 PCIe 结果(最佳)=\n");
    printf ("在%d 个周期内通过 PCIe 传递1个令牌往返(读取+写入)\n"、
    (unsigned int)(totalDMATime));
    printf ("==这不是优化的示例==\n");
    #endif

    其他

    /******** /
    /*等待来自 RC 的单个消息,然后将其回显 *
    /******** /

    /* EP 等待从 RC 接收到的数据*/
    执行{
    cache_invalidate (((void *) dstBuf.buf、PCIe_example_DSTBUF_Bytes);
    }while (dstBuf.buf[PCIe_BUFSIZE_APP]!= PCIe_Example_BUF_Full);

    printf ("端点接收到的数据。\n");

    /*回送至 RC 在 dst 缓冲区中写入的内容。
    从 EP 写入 RC */
    (i=0;<PCIE_BUFSIZE_APP; i++)

    pciedstBufBase->buf[i]= dstBuf.buf[i];


    /*标记缓冲区已满,因此 RC 可以处理它*/
    pciedstBufBase->buf[PCIe_BUFSIZE_APP]= PCIe_example_BUF_full;

    //注意高速缓存一致性:由于 pcieBase 位于中,因此不需要回写
    外设地址空间而不是物理内存*/

    printf ("端点已将数据发送到根复合体、完成回送。\n");
    #ifdef PCIe_REV1_HW
    /*将 msi 发送到 EP */
    pcieEpSendInts (手柄);
    #endif
    printf ("测试结束。\n"\});

    #ifdef PCIe_example_dma_ep
    IF (PcieExampleEdmaEP (pciedstBufBase、0xbabeface、100000、
    (EDMA3_DRV_Handle) hEdma)

    printf ("传递令牌失败\n");
    退出(1);

    printf ("端点发送数据到根复合体、DMA 完成回送。\n");
    printf ("DMA 测试结束。\n"\});
    #endif


    EDMA
    edmaDeinit (hEdma);
    #endif
    #ifdef EMDAPKTBENCH
    if (PcieEdmaPktBench (&dstBuf.edmaPktBenchBuf.msiTracker [0])、
    pciedstBufBase->edmaPktBenchBuf、
    PcieModeGbl、SEM)

    printf ("EDMA 数据包 IO 基准测试无法正确执行\n"\});
    退出(1);

    #endif
    printf ("测试通过。\n");
    #ifndef IO_console
    printf ("测试通过。\n");
    #endif

    // BIOS_exit (0);

    退出(0);





    void read_devStatCtrlReg (PCIe_Handle handle)

    pcieRegisters_t getRegs;
    pcieDevStatCtrlReg_t devStatCtrl;
    uint8_t val;

    memset (getRegs、0、sizeof (getRegs));
    memset (&devStatCtrl、0、sizeof (devStatCtrl));

    getRegs.devStatCtrl = devStatCtrl (&D);

    PCIe_readRegs (handle、PCIe_location_local、getRegs);

    Val =(getRegs.devStatCtrl->corrEr | getRegs.devStatCtrl->nFatalEr << 1 | getRegs.devStatCtrl->fatalEr << 2 | getRegs.devStatCtrl->rqDet << 3);

    如果(val = 1)

    printf ("检测到可纠正的错误\n");


    否则、如果(val = 2)

    printf ("检测到非致命错误\n");


    否则、如果(val = 4)

    printf ("检测到致命错误\n");


    否则、如果(val = 10)

    printf ("检测到不支持的请求错误\n");


    其他

    printf ("未检测到错误\n");

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

    感谢您共享代码。 它错过了 enableTxAndRxLoopback ()和 skipDetectStateIntssm()的实现。 我为他们编写了代码。 DEV_STAT_CTRL 读回寄存器为0x000A281F、是的、它设置了 UNSUP_RQ_DET 和 NFATAL_ERR 位。

    在正常的 PCIe RC 至 EP 设置中、我们通常将其设置为0x1281F、即设置的 corr_ERR 位。 虽然我没有详细说明为何设置这两个位、但我认为它来自 PHY 回送。 我可以写入"1"来清除它们。 因此您无需担心它。 如果稍后错误位再次置位、则需要对其进行调查。

    此致、Eric