Vinesh,
An update on what I have done. I have tried a couple more workarounds. A terrible hack that prevents the problem is a delay (busy wait) in the function CPSW_TxServiceCheck (found in cpsw_impl.c) before the call to read the completion pointer register. I put a simple for loop delay before this line:
Desc = CPSWCPDMATxCPGet(pd->Config.baseConfig.cpdma_base, i);
With the delay in place, the read of the register always comes back correct. The seems to indicate that the either 1) somehow the ISR is being called before the CPSW is done or 2) the CPSW peripheral is interrupting before it has properly set the completion pointer register value.
As a less bad workaround, I updated the function emacDequeueTx (also found in cpsw_impl.c) to check for the error condition. It ensures the pdc->DescCount is greater than or equal to the calculated descriptor count (which the function stores in the variable i). If that condition is not met, the second half of the function is skipped. The comment in the code explains why the workaround works. Code is:
--------------------------------------------------------------------------------------------------
/* Turn i into a descriptor count */
if( j < i )
i = (i-j)/sizeof(CPSW_Desc);
else
i = pdc->DescMax - ((j-i)/sizeof(CPSW_Desc));
/************ Addition - Josh Warr ***************************/
/* If DescCount is not greater than or equal to the number of descriptors
being acked, we must be looking at an old ack (t has been observed that
the Tx ISR is sometimes called before the Tx CP register reads
correctly). In this situation, we don't want to adjust DescCount, free
the buffers, or start any outstanding descriptors. Since in this condition the CP ack will be
different than what the port has written, per the spec the interrupt
will remain asserted, and we will recover in a future call to the
interrupt handler.*/
if (pdc->DescCount >= i)
{
/************ End Addition - Josh Warr ***************************/
if (pdc->DescCount == 0)
i = 0;
else
pdc->DescCount -= i;
/* Pop & \nFree Buffers 'till the last Descriptor */
while (((int)(i--)) > 0)
{
/* Recover the buffer and free it */
pPkt = pqPop(&pdc->DescQueue);
if (pPkt)
(*localDev.Config.pfcbFreePacket)(pdc->pd->hApplication,pPkt);
}
/* If the transmitter stopped and we have more descriptors, then restart */
if ((PktFlgLen & CPDMA_BUF_DESC_EOQ) && pdc->DescCount)
{
CPSWCPDMATxHdrDescPtrWrite(localDev.Config.baseConfig.cpdma_base, CPU_TO_HW(((Uint32)pdc->pDescRead)), pdc->chInfo->chNum);
}
/* Try to post any waiting TX packets */
if (pdc->WaitQueue.Count)
emacEnqueueTx(pdc);
/************ Addition - Josh Warr ***************************/
}
else
{
gl_retry_count++;
}
/************ End Addition - Josh Warr ***************************/
}
--------------------------------------------------------------------------------------------------
You can see that I added the global variable gl_retry_count to verify that the if condition is indeed preventing execution of those lines. As I run my application, gl_retry_count continually increases.
Any luck duplicating this issue on your end? Any suggestions for a cleaner workaround?
Thanks
--Josh