Hello,
Following application note for GOOSE forwarding ( https://www.ti.com/lit/ug/tidubo1/tidubo1.pdf ), barebone example should work and not report "taskPruss: link down" on IPU core. The example has been pulled from the git repo of tipde0074 ( https://git.ti.com/cgit/apps/tidep0074/tree/ipu1/PktProcEng.c ) with few minor changes (link status was down even before those changes).
We're using:
EDMA2_12_5
IPC3_47_1_0
BIOS6_73_0_12
PDK1_0_2
the first and most important change was in function "PRUICSS_create". "PRUICSS_create" always starts from PRU0_ICSS1. Since we changed which PRU that we're using (PRU0_ICSS2 and PRU1_ICSS2), we used function from pdk1_0_12, which allows to choose what PRU core to initialize with instance number.
The other change was introduced to server.c -> Server_exec. Here we removed everything regarding IPC communication and just left icss_tx in infinite while loop with 5 second interval.
pktProcEng.c (unchanged functions were omitted)
/*
* ---task to initialize PRU---
*/
Void taskPruss(void)
{
Uint8 firmwareLoad_done = FALSE;
System_printf("start task PRU-ICSS\n");
uint32_t pgVersion = (VHW_RD_REG32(
CSL_MPU_CTRL_MODULE_WKUP_CORE_REGISTERS_REGS +
CTRL_WKUP_ID_CODE) & 0xf0000000) >> 28;
PRUICSS_pruDisable(pruIcssHandle, ICSS_EMAC_PORT_1-1);
PRUICSS_pruDisable(pruIcssHandle, ICSS_EMAC_PORT_2-1);
#ifdef SOC_AM572x
if (pgVersion >= 2)
{
System_printf("taskPruss: Load FW to PG2.0 AM572x\n");
if(PRUICSS_pruWriteMemory(pruIcssHandle,PRU_ICSS_IRAM(0), 0,
(uint32_t *) PRU0_FIRMWARE_NAME,
sizeof(PRU0_FIRMWARE_NAME)))
{
if(PRUICSS_pruWriteMemory(pruIcssHandle,
PRU_ICSS_IRAM(1), 0,
(uint32_t *) PRU1_FIRMWARE_NAME,
sizeof(PRU1_FIRMWARE_NAME)))
firmwareLoad_done = TRUE;
}
}
else
{
if(PRUICSS_pruWriteMemory(pruIcssHandle,PRU_ICSS_IRAM(0), 0,
(uint32_t *) PRU0_FIRMWARE_V1_0_NAME,
sizeof(PRU0_FIRMWARE_V1_0_NAME)))
{
if(PRUICSS_pruWriteMemory(pruIcssHandle,
PRU_ICSS_IRAM(1), 0,
(uint32_t *) PRU1_FIRMWARE_V1_1_NAME,
sizeof(PRU1_FIRMWARE_V1_1_NAME)))
firmwareLoad_done = TRUE;
}
}
#else
if(PRUICSS_pruWriteMemory(pruIcssHandle,PRU_ICSS_IRAM(0) ,0,
(uint32_t *) PRU0_FIRMWARE_NAME,
sizeof(PRU0_FIRMWARE_NAME)))
{
if(PRUICSS_pruWriteMemory(pruIcssHandle,PRU_ICSS_IRAM(1) ,0,
(uint32_t *) PRU1_FIRMWARE_NAME,
sizeof(PRU1_FIRMWARE_NAME)))
firmwareLoad_done = TRUE;
}
#endif
if( firmwareLoad_done)
{
int32_t fbge = 5;
fbge = PRUICSS_pruEnable(pruIcssHandle, ICSS_EMAC_PORT_1-1);
System_printf("enable status 1: %d\n", fbge);
fbge = PRUICSS_pruEnable(pruIcssHandle, ICSS_EMAC_PORT_2-1);
System_printf("enable status 2: %d\n", fbge);
}
System_printf("sleeping 5 sec\n");
Task_sleep(5000);
while (!(((ICSS_EmacObject*)emachandle->object)->linkStatus[0] |
((ICSS_EmacObject*)emachandle1->object)->linkStatus[0]))
{
System_printf("linkStatus 1: %d, linkstatus 2: %d\n", ((ICSS_EmacObject*)emachandle->object)->linkStatus[0], ((ICSS_EmacObject*)emachandle1->object)->linkStatus[0]);
System_printf("taskPruss: link down\n");
Task_sleep(1000);
// ((ICSS_EmacObject*)emachandle->object)->linkStatus[0] = 1;
// ((ICSS_EmacObject*)emachandle1->object)->linkStatus[0] = 1;
}
System_printf("link is finally up \n");
ICSS_EmacRegisterHwIntRx(emachandle, (ICSS_EmacCallBack)testCallbackRxPacket);
//ICSS_EmacRegisterHwIntRx(emachandle1, testCallbackRxPacket);
}
/**
* @brief initialize PRU & ICSS_EMAC config parameters due to MMU in IPU
*
* @param none
*
* @retval none
*/
void initPruIcssEmacCfg()
{
uint32_t i;
/* phys. to virt translation for prussInitCfg[0], [1]*/
for(i=0; i<sizeof(PRUICSS_HwAttrs)/2; i++)
*((uint32_t *)prussInitCfg + i) += VIRT0;
prussInitCfg[0].version = 0;
prussInitCfg[1].version = 0;
/* phys. to virt translation for ICSS_EmacBaseAddrCfgParams[0], [1]*/
for(i=0; i<sizeof(ICSS_EmacBaseAddrCfgParams)/2; i++)
*((uint32_t *)icss_EmacBaseAddrCfgParams + i) += VIRT0;
}
PRUICSS_Handle PRUICSS_create1(PRUICSS_Config *config ,int32_t instance);
PRUICSS_Handle PRUICSS_create1(PRUICSS_Config *config ,int32_t instance)
{
PRUICSS_Handle handle;
PRUICSS_V1_Object *object;
PRUICSS_HwAttrs const *hwAttrs;
uint32_t temp_addr = 0U;
uint32_t temp_val;
handle = (PRUICSS_Config *)&config[instance-1];
hwAttrs = (PRUICSS_HwAttrs const *)handle->hwAttrs;
object = (PRUICSS_V1_Object*)handle->object;
object->instance = instance;
// REVID register is offset by 0 in AM5728,
// othervise you should put "CSL_ICSSCFG_REVID"
temp_addr = (hwAttrs->prussCfgRegBase + 0/*CSL_ICSSCFG_REVID*/);
temp_val = HWREG(temp_addr) & 0xFFFFU;
object->pruicss_version = temp_val;
return(&config[instance-1]);
}
/**
* @brief PRU & ICSS_EMAC initialization
*
* @param none
*
* @retval 0: success
* -1: rx semaphore creation failed
* -2: rx task creation failed
*/
int pru_icss()
{
Error_Block eb;
Task_Params taskParams;
SemaphoreP_Params semParams;
Error_init(&eb);
initPruIcssEmacCfg();
pruIcssHandle = PRUICSS_create1((PRUICSS_Config *)pruss_config, PRUICCSS_INSTANCE_TWO);
Task_Params_init(&taskParams);
taskParams.priority = 15;
taskParams.instance->name = "SwitchTask";
Task_create((Task_FuncPtr)taskPruss, &taskParams, &eb);
/*ETH0 initializations*/
emachandle = (ICSS_EmacHandle)malloc(sizeof(ICSS_EmacConfig));
ICSS_EmacInitConfig* switchEmacCfg;
switchEmacCfg = (ICSS_EmacInitConfig*)malloc(sizeof(ICSS_EmacInitConfig));
switchEmacCfg->phyAddr[0] = 0;
switchEmacCfg->portMask = ICSS_EMAC_MODE_MAC1;
switchEmacCfg->ethPrioQueue = ICSS_EMAC_QUEUE1;
/* Crosssbar confiiguration */
*(unsigned int*)(0x4A0027E8U + VIRT0) =(unsigned int)(0x00C400CA);
*(unsigned int*)(0x4A0027ECU + VIRT0) =(unsigned int)(0x00CB00C5);
switchEmacCfg->halfDuplexEnable = 1;
switchEmacCfg->enableIntrPacing = ICSS_EMAC_ENABLE_PACING;
switchEmacCfg->ICSS_EmacIntrPacingMode = ICSS_EMAC_INTR_PACING_MODE1;
switchEmacCfg->pacingThreshold = 100;
switchEmacCfg->learningEn = 0;
SOCCtrlGetPortMacAddr(0,lclMac);
switchEmacCfg->macId = lclMac;
ICSSEmacDRVInit(emachandle, 2);
switchEmacCfg->rxIntNum = 70;
switchEmacCfg->linkIntNum = 69;
((ICSS_EmacObject*)emachandle->object)->pruIcssHandle = pruIcssHandle;
((ICSS_EmacObject*)emachandle->object)->emacInitcfg = switchEmacCfg;
/*ETH1 initializations*/
emachandle1 = (ICSS_EmacHandle)malloc(sizeof(ICSS_EmacConfig));
ICSS_EmacInitConfig* switchEmacCfg1;
switchEmacCfg1 = (ICSS_EmacInitConfig*)malloc(sizeof(ICSS_EmacInitConfig));
switchEmacCfg1->phyAddr[0] = 1;
switchEmacCfg1->portMask = ICSS_EMAC_MODE_MAC2;
switchEmacCfg1->ethPrioQueue = ICSS_EMAC_QUEUE3;
switchEmacCfg1->enableIntrPacing = ICSS_EMAC_DISABLE_PACING;
switchEmacCfg1->pacingThreshold = 100;
switchEmacCfg1->learningEn = 0;
SOCCtrlGetPortMacAddr(1,lclMac1);
switchEmacCfg1->macId = lclMac1;
ICSSEmacDRVInit(emachandle1, 2);
switchEmacCfg1->rxIntNum = 78;
switchEmacCfg1->linkIntNum = 75;
((ICSS_EmacObject*)emachandle1->object)->pruIcssHandle = pruIcssHandle;
((ICSS_EmacObject*)emachandle1->object)->emacInitcfg = switchEmacCfg1;
PRUICSS_IntcInitData pruss_intc_initdata = PRUSS_INTC_INITDATA;
ICSS_EmacInit(emachandle,&pruss_intc_initdata,ICSS_EMAC_MODE_MAC1);
ICSS_EmacInit(emachandle1,&pruss_intc_initdata,ICSS_EMAC_MODE_MAC2);
Task_Params_init(&taskParams);
taskParams.priority = 10;
taskParams.instance->name = (char*)"port0_rxTaskFnc";
taskParams.stackSize = 0x1000;
taskParams.arg0 = (UArg)emachandle;
((ICSS_EmacObject*)emachandle->object)->rxTaskHandle =
Task_create(ICSS_EMacOsRxTaskFnc, &taskParams, NULL);
if(((ICSS_EmacObject*)emachandle->object)->rxTaskHandle==NULL)
return -2;
Task_Params_init(&taskParams);
taskParams.priority = 10;
taskParams.instance->name = (char*)"port1_rxTaskFnc";
taskParams.stackSize = 0x1000;
taskParams.arg0 = (UArg)emachandle1;
((ICSS_EmacObject*)emachandle1->object)->rxTaskHandle =
Task_create(ICSS_EMacOsRxTaskFnc, &taskParams, NULL);
if(((ICSS_EmacObject*)emachandle1->object)->rxTaskHandle==NULL)
return -2;
PRUICSS_pinMuxConfig(pruIcssHandle, 0x0);
InterruptInit(emachandle);
InterruptInit(emachandle1);
EMACOpen(emachandle, 2);
// EMACOpen(emachandle1, 2);
EnableEMACInterrupts(emachandle);
EnableEMACInterrupts(emachandle1);
semParams.mode = SemaphoreP_Mode_COUNTING;
semParams.name= "icss_rxSemaphore";
icssRxSem = SemaphoreP_create(0,&semParams);;
if(icssRxSem == NULL)
return -1;
semParams.mode = SemaphoreP_Mode_COUNTING;
semParams.name= "icss_rxSemaphore1";
icssRxSem1 = SemaphoreP_create(0,&semParams);;
if(icssRxSem1 == NULL)
return -1;
System_printf("main_pruss: initialization done!\n");
return(0);
}
/**
* @brief Get MAC address
*
* @param portNum: port number
* pMacAddr: MAC address data pointer
*
* @retval none
*/
void SOCCtrlGetPortMacAddr(uint32_t portNum, uint8_t *pMacAddr)
{
if(portNum == 0) {
pMacAddr[5U] = (VHW_RD_REG32(0x4A002514)
>> 0U) & 0xFFU;
pMacAddr[4U] = (VHW_RD_REG32(0x4A002514)
>> 8U) & 0xFF;
pMacAddr[3U] = (VHW_RD_REG32(0x4A002514)
>> 16U) & 0xFFU;
pMacAddr[2U] = (VHW_RD_REG32(0x4A002518)
>> 0U) & 0xFFU;
pMacAddr[1U] = (VHW_RD_REG32(0x4A002518)
>> 8U) & 0xFFU;
pMacAddr[0U] = (VHW_RD_REG32(0x4A002518)
>> 16U) & 0xFFU;
}
else {
pMacAddr[5U] = (VHW_RD_REG32(0x4A00251c)
>> 0U) & 0xFFU;
pMacAddr[4U] = (VHW_RD_REG32(0x4A00251c)
>> 8U) & 0xFF;
pMacAddr[3U] = (VHW_RD_REG32(0x4A00251c)
>> 16U) & 0xFFU;
pMacAddr[2U] = (VHW_RD_REG32(0x4A002520)
>> 0U) & 0xFFU;
pMacAddr[1U] = (VHW_RD_REG32(0x4A002520)
>> 8U) & 0xFFU;
pMacAddr[0U] = (VHW_RD_REG32(0x4A002520)
>> 16U) & 0xFFU;
}
}
we identified a possible issue :
- wrong MAC address retrieval: function SOCCtrlGetPortMacAddr returns different MAC address that is eth2 and eth3 interface, and is always constant. MAC addresses are randomly initialized for port1 and 2 during booting
[ 4.243312] prueth pruss2_eth: port 1: using random MAC addr: 2e:7c:13:0c:a2:db
[ 4.308953] prueth pruss2_eth: port 1: using random MAC addr: 92:5b:94:07:ac:08
[ 4.312874] prueth pruss2_eth: port 2: using random MAC addr: a6:07:29:c5:f3:12
[ 4.329570] prueth pruss2_eth: port 1: using random MAC addr: 3a:b7:41:ab:21:a6
[ 4.341593] prueth pruss2_eth: port 2: using random MAC addr: 8a:00:7d:2c:d9:76
we tried to force the randomly assigned MAC address by directly changing lclMac and lclMac1 after the SOCCtrlGetPortMacAddr finished, yet the link still wouldn't get up.
trace for IPU (added linkStatus 1: 0, linkstatus 2: 0 by myself):
[0][ 0.000] start task PRU-ICSS
[0][ 0.000] taskPruss: Load FW to PG2.0 AM572x
[0][ 5.000] linkStatus 1: 0, linkstatus 2: 0
[0][ 5.000] taskPruss: link down
[0][ 6.000] linkStatus 1: 0, linkstatus 2: 0
etc... repeats forever
Have to add: PRU are fine, since we are able to use all 3 ethernet ports (2 of which are over PRU cores) to ping both directions and connect to am5728 via SSH. that is possible only if we use this firmwares:
am57xx-pru0-prueth-fw.elf
am57xx-pru1-prueth-fw.elf
so it has to be something with the IPU<->PRU part