Altera_Forum
Honored Contributor
14 years agoSGDMA Callback fires more often than i restart the SGDMA
Hi,
i have some trouble with SGDMA and TSE. I guess the problem is in the callback function(_ISR_HanderRX) of the RX-SGDMA. Ok let's explain this stuff a little bit: After first init of the RX-SGDMA the _ISR_HandlerRX function should be called when the descriptor chain is completed. In the ISR_HandlerRX function the Interrupt should be cleared and the tcp/ip stack shall be informed that a new packed has arrived. Then the tcp/ip stack will call the _ReadPacket function and after running this code, the RX-SGDMA shall be reseted for the next turn. Problem is, the counters in these functions show me, that the _ISR_HandlerRX functions is called way more often than the _ResetRX function, can anyone explain me why this is happening, i thought that i stopped the interrupt in the ISR_HandlerRx function??? Here is the Code, also appended as txt-file. Thx Christian
static void _ISR_HandlerRX(void * context, u_long intnum)
{
aCounter++; //testcounter a
// Interrupt clearen und Run-Bit zurücksetzen
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, ALTERA_AVALON_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK & ~ALTERA_AVALON_SGDMA_CONTROL_RUN_MSK);
// inform TCP/IP stack about new packet
IP_OnRx();
bCounter++; //testcounter b
}
static int _ReadPacket(unsigned Unit, U8 *pDest, unsigned NumBytes)
{
volatile UInt32 ulPacketLengthFromSgdmaRX = 0x00,
i = 0x00;
volatile UChar8 * pRxBuff = NULL;
cCounter++; //testcounter c
ulPacketLengthFromSgdmaRX = pSgdmaDescriptor.actual_bytes_transferred;
if(IORD_ALTERA_TSEMAC_RX_CMD_STAT(TSE_MAC_BASE) & ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK && ulRxPacketSize > 0)
ulPacketLengthFromSgdmaRX -= 2; // when the shift option is used, the length read from the status word is 2 bytes larger than the real frame size, adjust counter!
if(NumBytes == ulPacketLengthFromSgdmaRX)
{
/* test for errors */
if (((pSgdmaDescriptor.status)
& ( ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | // crc error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK | // parity error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK | // overflow error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK | // sync error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK | // end of package error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK | // end of package error
ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK )) // start of package error
== 0)
{
pRxBuff = pUncachedPtrRx + 2; // pointer to the first field, where the data begins
while(NumBytes) // copy all data
{
pDest = *pRxBuff++;
i++;
NumBytes--;
}
}
}
dCounter++; //testcounter d
_ResetRx();
return 0;
}
static int _ResetRx(void)
{
volatile alt_u32 timeout=0,
ulSgdmaCtrl = 0x00;
eCounter++; //testcounter e
/*SGDMA RX Softwarereset*/
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0);
memset((void*) cRxBufferTmp, 0x00, BUFF_SIZE);
memset((void*) &pSgdmaDescriptor , 0x00, sizeof(alt_sgdma_descriptor));
//pUncachedPtrRx = alt_remap_uncached((void*)cRxBufferTmp, BUFF_SIZE);
/* rx-sgdma descriptor konstruieren */
alt_avalon_sgdma_construct_stream_to_mem_desc ((alt_sgdma_descriptor *) &pSgdmaDescriptor , // descriptor I want to work with
(alt_sgdma_descriptor *) &pSgdmaDescriptor , // pointer to "next"
(UInt32 *)pUncachedPtrRx, // starting write_address
0, // read until EOP
0); // don't write to constant address
/* register callback for rx-sgdma */
alt_avalon_sgdma_register_callback ((alt_sgdma_dev *) pRxSgdmaDev,
(alt_avalon_sgdma_callback) &_ISR_HandlerRX, /* callbackfunction for the interrupt */
(ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), /* interrupt if chain completed */
NULL);
/* Make sure SGDMA controller is not busy from a former command */
while ((IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK))
{
if(timeout++ == ALTERA_TSE_SGDMA_BUSY_TIME_OUT_CNT)
return ENP_RESOURCE; // avoid being stuck here
}
IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE, 0xff); //clear status register (look at documentation of sgdma status reg)
/* SGDMA operation invoked for RX (non-blocking call) */
if(alt_avalon_sgdma_do_async_transfer((alt_sgdma_dev *) pRxSgdmaDev, (alt_sgdma_descriptor *) &pSgdmaDescriptor ) != 0)
return -1;
ulSgdmaCtrl = IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE); // read SGDMA Ctrl Register
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE, ulSgdmaCtrl | ALTERA_TSE_SGDMA_INTR_MASK); //write SGDMA Ctrl Regs
fCounter++; //testcounter f
return 0;
}