/**************************************************************************************** * ddc_sar_init.c * DDC UR8 SAR implementation. * * 2006 (c) Texas Instruments Inc. * * 8/18/2006 AV & GSG Adapted the original version from Adam2. * 9/15/2006 AV Updated with the changes for the new memory map * for the PDSP. * 9/26/2006 AV Enabling the Rx channel close. Removing the by-passing of * the CPPI calls for the RX channel open. * 10/12/2006 AV Removing unused code. Removing the unnecessary params * from ddc_cpsarDDCStats(). * 10/25/2006 AV CQ11118:Fixing the UnInitTxChannel() for channel close. Adding a * sleep for Rx channel close. * 10/27/2006 AV CQ11118:Adding a sleep for Tx channel close. * 10/29/2006 AV Updating the DDC_malloc_rxbuffer() API to pass in the size. * 10/29/2006 AV CQ11117:Changing the allocation and deallocation of the RX BDs, to be done * on a per queue basis, as opposed to per channel basis. * 10/31/2006 AV CQ11118:Disabling the call to PAL_cppi4DisableTxIntr() and PAL_cppi4DisableRxIntr() * as it currently clears all the interrupts. These should be re-enabled * when the fix is provided from the BasePSP. * 11/17/2006 EP Added big endian support. * 12/01/2006 CPH/MK Added more channel qos information in ddc_cpsarDDCStats(). (avsar_sarhal_stats proc). * 01/09/2007 EP Added one counter for multiple BD recycling. * 02/07/2007 MK CQ11291: Added OAM ping support. * 01/29/2007 CZ CQ11294: fix Unloading DSL driver module * 02/14/2007 EP Added env var for CPPI error handling. ****************************************************************************************/ #include "ddc_cpsardrv.h" #include "av_sar_loop_firm.h" #include "av_sar_firm.h" //CZ #include "ddc_ti_dsl.h" /* Static Global Instance Variable */ static Bool CpsarDDCInstCreated[CPSAR_MAX_INSTANCES] = { False }; static CpsarDDCObj *CpsarDDCObject[CPSAR_MAX_INSTANCES] = { NULL }; static unsigned int CpsarDDCNumInst = 0; static int cpsarInitPdsp(CpsarDDCObj *hDDC); static void cpsarOamRateConfig(CpsarDDCObj *hDDC); static int cpsarDisableChannel(CpsarDDCObj *hDDC, unsigned int channel, DDC_NetChDir direction); static int cpsarUnInitTxChannel(CpsarDDCObj *hDDC, unsigned int channel, void * chCloseArgs); static int cpsarUnInitRxChannel(CpsarDDCObj *hDDC, unsigned int channel, void * chCloseArgs); static int ddc_sar_init_cppi4Config(CpsarDDCObj *hDDC, CpsarChInfo *chInfo, unsigned int QNum); static int ddc_sar_init_config_params(CpsarDDCObj *hDDC, int useLB); /** * DDC_cpsarCreateInstance * - exchange handles and function pointers between DDA/DDC * * \note 1. Unless function pointers are exchanged, error log and debug printf * statements cannot be used in this function. Hence we dont log * anything in this function. * 2. "param" is not used in this implementation */ int DDC_cpsarCreateInstance(unsigned int instId, DDA_Handle hDDA, CpsarDDCObj **hDDC, void * param) { CpsarDDCObj *cpsarDDCHandle; int retCode = CPSAR_SUCCESS; /* Check CPSAR instance */ if (CpsarDDCInstCreated[instId] == True) { return (CPSAR_ERR_DEV_ALREADY_INSTANTIATED(instId)); } /* Allocate memory for CPSAR DDC Instance Object and set to 0 */ retCode = PAL_osMemAlloc(0, sizeof(CpsarDDCObj), 0, (void * *) &cpsarDDCHandle); if (retCode != PAL_SOK) { return (retCode); } PAL_osMemSet(cpsarDDCHandle, 0, sizeof(CpsarDDCObj)); /* Set CPSAR object variables */ cpsarDDCHandle->versionId = (CPSAR_DDC_MAJOR_VERSION << 16) | CPSAR_DDC_MINOR_VERSION; cpsarDDCHandle->instId = instId; cpsarDDCHandle->state = DDC_CREATED; cpsarDDCHandle->hDDA = hDDA; /* Pass back DDC Object handle and Interface Table handle */ *hDDC = (DDC_Handle) cpsarDDCHandle; /* Update "instance created" variable */ CpsarDDCInstCreated[instId] = True; CpsarDDCObject[instId] = cpsarDDCHandle; ++CpsarDDCNumInst; return (retCode); } /** * DDC_cpsarInit * - validates max TX/RX channels and stores initial configuration * * \note Initial configuration passed by DDA via the "initCfg" parameter */ int DDC_cpsarInit(CpsarDDCObj *hDDC, unsigned int useLB) { int retCode; unsigned int i; CpsarInitConfig *initCfg; volatile unsigned int *pTmp; LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ DDC_cpsarInit %d", hDDC->instId); /* Save config info for later use */ //AV_SM : TODO Doing the initialization of the data structures here for the configuration. if(ddc_sar_init_config_params(hDDC, useLB)) { //DDA_free(SarDev); return (CPSAR_ERROR_CRITICAL); } LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ DDC_cpsarOpen:%d:", hDDC->instId); if (hDDC->state == DDC_OPENED) { DDA_printf("\nERROR:%s:%d: Device already open", __FUNCTION__ , hDDC->instId); return (CPSAR_ERR_DEV_ALREADY_OPEN); } /* Connect to the CPPI4 PAL, take NWSS out of reset */ hDDC->cppi4PAL = PAL_cppi4Init(&hDDC->initCfg.cppi4InitCfg, NULL); if(hDDC->cppi4PAL == NULL) { DDA_printf("\nERROR:%s: Error %08X from CPPI4 PAL Init()",__FUNCTION__); return (CPSAR_ERROR_MAJOR); } /* Get init config info structure pointer for easy access */ initCfg = &hDDC->initCfg; hDDC->regs = (CSL_SarRegsOvly) initCfg->baseAddress; hDDC->scratchpad_regs = (CSL_ScratchpadRegsOvly) initCfg->scratchpadAddress; /* Configure UNI/NNI */ hDDC->regs->Rx_LUT_Global_Config |= initCfg->uniNni; /* Clear entire PDSP state RAM */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[0].AAL5_Tx_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[0].Reserved[0]; #endif for (i=0; iscratchpad_regs->PDSP_CH_RAM[i].AAL5_Rx_State[0] |= (initCfg->oamMode << 8); #else hDDC->regs->PDSP_RAM[i].AAL5_Rx_State[0] |= (initCfg->oamMode << 8); #endif /* Initialize PDSP */ retCode = cpsarInitPdsp(hDDC); if(retCode) return(retCode); /* Reset and Enable the PDSP */ hDDC->regs->Control = 0x00080003; /* OAM Configuration */ /* Configure OAM Timer State Block */ cpsarOamRateConfig(hDDC); /* Setup OAM Configuration Block */ for (i=0; i<8; i++) { if (i < 4) { #ifndef SAR_OLD hDDC->scratchpad_regs->PDSP_OAM_RAM.OAM_Config[i] = hDDC->initCfg.deviceCPID[i]; #else hDDC->regs->PDSP_RAM[3].PDSP_General_Use[4+i] = hDDC->initCfg.deviceCPID[i]; #endif } else { #ifndef SAR_OLD hDDC->scratchpad_regs->PDSP_OAM_RAM.OAM_Config[i] = hDDC->initCfg.lbSourceLLID[i-4]; #else hDDC->regs->PDSP_RAM[3].PDSP_General_Use[4+i] = hDDC->initCfg.lbSourceLLID[i-4]; #endif } } /* Setup OAM Padding Block */ for (i=0; i<12; i++) { #ifndef SAR_OLD hDDC->scratchpad_regs->PDSP_OAM_RAM.OAM_Padding[i] = ((i==11)?0x6a6a0000:0x6a6a6a6a); #else hDDC->regs->PDSP_RAM[4].PDSP_General_Use[4+i] = ((i==11)?0x6a6a0000:0x6a6a6a6a); #endif } /* Enable Host Interrupt for GPR 2 (OAM LB result register) */ hDDC->regs->Host_Int_Enable_Set |= 0x04000000; /* Set device state - Opened - useful when opening channels */ hDDC->state = DDC_OPENED; LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- DDC_cpsarInit:%d:", hDDC->instId); return (CPSAR_SUCCESS); } /** * cpsarInitPdsp * - chooses between loopback and regular firmware, and writes one * of them into the instruction RAM. * - it is assumed that the SAR has been taken out of reset */ static int cpsarInitPdsp(CpsarDDCObj *hDDC) { unsigned int NumOfEntries,i,IRamAddress,iTmp,FirmwareSize; unsigned int *FirmwarePtr; IRamAddress = (unsigned int) &hDDC->regs->PDSP_IRAM[0]; /* which firmware to use? */ if (hDDC->initCfg.useLoopFirmware == 1) { FirmwarePtr = (unsigned int *)hDDC->initCfg.loopFirmware; FirmwareSize = hDDC->initCfg.loopFirmwareSize; DDA_printf("%s: Using loopback SAR firmware \n", __FUNCTION__); } else { FirmwarePtr = (unsigned int *)hDDC->initCfg.firmware; FirmwareSize = hDDC->initCfg.firmwareSize; } /* check firmware size first */ NumOfEntries = FirmwareSize/4; if (NumOfEntries > IRAM_SIZE) { return(CPSAR_ERR_FIRMWARE_TOO_LARGE); } /* program firmware to iram */ for(i=8;iinitCfg.cpsarBusFrequency, i; /* Configure OAM Timer State Block */ for (i=0; iinitCfg.oamLbTimeout); break; case 1: case 2: case 5: case 6: case 7: case 8: OamRate = (Freq/38); break; case 3: case 4: OamRate = ((Freq*3) + (Freq/2))/38; break; case 9: case 10: OamRate = ((Freq*2) + (Freq/2))/38; break; default: OamRate = (Freq*5); break; } /* Configure OAM TIMER RATE */ #ifndef SAR_OLD hDDC->scratchpad_regs->PDSP_CH_RAM[i+5].PDSP_General_Use[1] = OamRate; #else hDDC->regs->PDSP_RAM[i+5].PDSP_General_Use[1] = OamRate; #endif } } /** * cpsarEnableChannel * - Channel is enabled in hardware. Data transfer ready. * * \note 1. It is assumed that the channel is already "initialized" * 2. To enable a channel after its disabled, it needs to be */ static int cpsarEnableChannel(CpsarDDCObj *hDDC, unsigned int channel, unsigned int direction) { volatile unsigned int *pTmp; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarEnableChannel:%d: Ch=%d, Direction=%s", hDDC->instId, channel, ((direction==DDC_NET_CH_DIR_TX) ? "TX" : "RX")); if (direction == DDC_NET_CH_DIR_TX) { CpsarTxCppiCh *txCppi; unsigned int txCompQueue; void * cppi4TxChHnd; unsigned int retCode; txCppi = &hDDC->txCppi[channel]; if(txCppi->chInfo.chState != DDC_NET_CH_INITIALIZED) { DDA_printf("\nERROR:DDC: cpsarEnableChannel:%d: Invalid Channel %d. TX CPPI structure NULL", hDDC->instId, channel ); return (CPSAR_ERR_TX_CH_INVALID); } /* Setup TX PDSP State RAM */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Tx_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Tx_State[0]; #endif *pTmp++ = txCppi->chInfo.TxVc_CellRate; /* Set the cell rate in cells/sec */ *pTmp++ = txCppi->chInfo.TxVc_QosType; /* Configure the QoS Type */ *pTmp++ = txCppi->chInfo.TxVc_Mbs; /* Set minimum burst size */ *pTmp++ = 0; /* (skip a register) */ *pTmp++ = txCppi->chInfo.TxVc_Pcr; /* set the peak cell rate */ *pTmp++ = 0; /* (skip a register) */ *pTmp++ = txCppi->chInfo.AtmHeader; /* give the ATM header */ *pTmp++ = (txCppi->chInfo.TxVc_OamTc << 8) |(txCppi->chInfo.TxVc_VpOffset); /* Set the OAM TC Path and VP Offset */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Tx_VP_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Tx_VP_State[0]; #endif *pTmp++ = txCppi->chInfo.AtmHeader &~ ATMHEADER_VCI_MASK; *pTmp++ = (txCppi->chInfo.TxVp_OamTc << 8); *pTmp++ = 0; *pTmp++ = 0; /* Configure Tx Scheduler Channel Config Register (turn channel "ON") */ hDDC->regs->TXS_Channel_Config = 0x80000000 | (txCppi->chInfo.DaMask << 30) | (txCppi->chInfo.Priority << 24) | channel; /* Configure the atm header and cpcs_uu fields for the tx channel */ hDDC->scratchpad_regs->AtmHeader[channel] = txCppi->chInfo.AtmHeader; hDDC->scratchpad_regs->CpcsUU[channel] = txCppi->chInfo.CpcsUU; /* Hook interrupt handlers and enable them */ txCompQueue = txCppi->chInfo.cppi4TxChInfo.cqIndex; hDDC->txIntLineCount[txCompQueue] += 1; /* Open the channel in the CPPI4 PAL */ cppi4TxChHnd = PAL_cppi4TxChOpen(hDDC->cppi4PAL,&txCppi->chInfo.cppi4TxChInfo, NULL); if (cppi4TxChHnd == NULL) { DDA_printf("\nERROR:%s: Error from CPPI4 PAL TxChOpen() for ch %d",__FUNCTION__, channel); return (CPSAR_INTERNAL_FAILURE); } txCppi->cppi4TxChHnd = cppi4TxChHnd; DDA_printf("%s: Registered channel with 0x%p handle \n",__FUNCTION__, cppi4TxChHnd); retCode = PAL_cppi4EnableTxChannel(txCppi->cppi4TxChHnd, NULL); if(retCode != PAL_SOK) { DDA_printf("\nERROR:cpsarEnableChannel: Error %08X from CPPI4 PAL EnableTxChannel()", retCode); return (retCode); } /* If this is the first channel to use this completion queue, connect the interrupt handler */ if (hDDC->txIntLineCount[txCompQueue] == 1) { /* * Hook interrupt handlers and enable them. * @note - Tx interrupt line number is calculated from the cqIndex. */ hDDC->txIntLine[txCompQueue] = txCompQueue + CPPI4_MIN_TX_INT_LINE; retCode = PAL_cppi4EnableTxIntr(txCppi->cppi4TxChHnd, NULL); if(retCode != PAL_SOK) { DDA_printf("\nERROR:cpmacEnableChannel: Error %08X from CPPI4 PAL EnableTxIntr()", retCode); return (retCode); } } /* Mark channel open */ hDDC->txIsOpen |= channel_mask; txCppi->chInfo.chState = DDC_NET_CH_OPENED; } else if (direction == DDC_NET_CH_DIR_RX) { CpsarRxCppiCh *rxCppi; unsigned int rxQueue; void * cppi4RxChHnd; unsigned int retCode; BdMemChunk *MemChunk; unsigned int cnt; Cppi4BD *currBD; unsigned int lockKey; rxCppi = &hDDC->rxCppi[channel]; if (rxCppi == NULL) { DDA_printf("\nERROR:DDC: cpsarEnableChannel:%d: Invalid Channel %d. RX CPPI structure NULL", hDDC->instId, channel ); return (CPSAR_ERR_RX_CH_INVALID); } /* Setup RX PDSP State RAM */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Rx_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Rx_State[0]; #endif *pTmp++ = (rxCppi->chInfo.RxVc_OamCh) | (hDDC->initCfg.oamMode << 8) | (rxCppi->chInfo.RxVc_OamToHost<<9); /* Set OAM Channel, Mode, and ToHost options */ *pTmp++ = rxCppi->chInfo.AtmHeader; /* ATM hdr put on firmware generated OAM */ *pTmp++ = (rxCppi->chInfo.RxVc_VpOffset)| /* Set Rx OAM TC Path and VP Offset */ (rxCppi->chInfo.RxVc_OamTc<<8); *pTmp++ = 0; *pTmp++ = 0; *pTmp++ = 0; *pTmp++ = 0; *pTmp++ = 0; #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Rx_VP_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Rx_VP_State[0]; #endif *pTmp++ = rxCppi->chInfo.AtmHeader &~ ATMHEADER_VCI_MASK; *pTmp++ = (rxCppi->chInfo.RxVp_OamCh)| (rxCppi->chInfo.RxVp_OamTc<<8)| (rxCppi->chInfo.RxVp_OamToHost<<9); /* Set OAM Channel, Mode, and ToHost options */ *pTmp++ = 0; *pTmp++ = rxCppi->chInfo.RxVp_OamVcList; /* Setup Rx Channel in the LUT */ if (!(hDDC->regs->Rx_LUT_Ch_Setup_Req & 0x80000000)) { return(CPSAR_ERR_LUT_NOT_READY); } DDA_printf("Atmheader = %08x\n", rxCppi->chInfo.AtmHeader); /* RX LUT is ready */ hDDC->regs->Rx_LUT_Ch_Setup_Req = (rxCppi->chInfo.PktType << 24) | channel; hDDC->regs->Rx_LUT_Ch_Setup_Req_VPI_VCI = rxCppi->chInfo.AtmHeader & ATMHEADER_VPI_VCI_MASK; /* Open the channel in the CPPI4 PAL */ cppi4RxChHnd = PAL_cppi4RxChOpen(hDDC->cppi4PAL,&rxCppi->chInfo.cppi4RxChInfo, NULL); if (cppi4RxChHnd == NULL) { DDA_printf("\nERROR:DDC: cpsarEnableChannel: Error from CPPI4 PAL RxChOpen()"); return (CPSAR_INTERNAL_FAILURE); } rxCppi->cppi4RxChHnd = cppi4RxChHnd; /* * Hook interrupt handlers and enable them. * @note - Rx interrupt line number is calculated from the rqIndex. */ rxQueue = rxCppi->chInfo.cppi4RxChInfo.rqIndex; hDDC->rxIntLineCount[rxQueue] += 1; //AV_FIX_BD : CQ11117 /* If this is the first ch to use this rxQueue, then allocate the BDs */ if (hDDC->rxIntLineCount[rxQueue] == 1) { /* Allocate the rxBufferPtr and rxDataToken arrays based on rxMaxFrags */ retCode = PAL_osMemAlloc(0, sizeof(BdMemChunk), 0, (Ptr *)&MemChunk); if (retCode != PAL_SOK) { DDA_printf("\nERROR:%s:%d: Failed to allocate mem chunk for RX CPPI Ch %d", __FUNCTION__, hDDC->instId,rxCppi->chInfo.chNum ); return (CPSAR_INTERNAL_FAILURE); } /* Set memory to 0 */ PAL_osMemSet(MemChunk, 0, sizeof(BdMemChunk)); MemChunk->bdMemSize = (sizeof(Cppi4BD) * rxCppi->chInfo.RxNumBuffers); /* Allocate BD Pool*/ retCode = PAL_osMemAlloc(0, MemChunk->bdMemSize, CPPI4_BD_ALIGN, (Ptr *)&MemChunk->bdMemPtr); if (retCode != PAL_SOK) { DDA_printf("\nERROR:%s:%d: Failed to allocated mem for BD pool memory for RX CPPI Ch %d", __FUNCTION__, hDDC->instId,rxCppi->chInfo.chNum); PAL_osMemFree(0, MemChunk->bdMemPtr, MemChunk->bdMemSize); return(CPSAR_INTERNAL_FAILURE); } /* Set memory to 0 */ PAL_osMemSet(MemChunk->bdMemPtr, 0, MemChunk->bdMemSize); /* Allocate RX buffer and initialize the BD linked list */ currBD = (Cppi4BD *)MemChunk->bdMemPtr; /* Save the BD count in the mem chunk, will be used for freeing later */ MemChunk->numBd = rxCppi->chInfo.RxNumBuffers; /* "Slice" BD's one-by-one from the chunk, allocate a buffer and token, */ DDA_printf("%s: Allocating %d buffer descriptors at 0x%p \n",__FUNCTION__, rxCppi->chInfo.RxNumBuffers, MemChunk); DDA_printf("%s: RX Service Max is set to %d \n",__FUNCTION__, rxCppi->chInfo.RxServiceMax); for (cnt = 0; cnt < rxCppi->chInfo.RxNumBuffers; cnt++) { char *newBuffer; void *newBufToken; newBuffer = (char *) DDC_malloc_rxbuffer(hDDC->hDDA, &newBufToken, rxCppi->chInfo.RxBufSize, rxCppi->chInfo.chNum); if (newBuffer == NULL) { DDA_printf("\nERROR:DDC: %s: Error in RX Buffer allocation for channel %d", __FUNCTION__, rxCppi->chInfo.chNum); PAL_osMemFree(0, MemChunk->bdMemPtr, MemChunk->bdMemSize); return (CPSAR_INTERNAL_FAILURE); } /* Update the hardware descriptor */ currBD->nextPktPtr = 0; /* Technically, this shouldn't be required. However, I need to guarantee that packet length was set to 0, because it is checked for in RxBDProc. There is a case where packet length can be 0 and no error has occurred, if an Rx teardown has occurred */ currBD->pktInfo = 0; currBD->off_bLen = rxCppi->chInfo.RxBufSize & 0xffff; currBD->buf0Ptr = CPSAR_VIRT_2_PHYS(newBuffer); currBD->dataPtr = (Ptr) newBuffer; currBD->bufToken = newBufToken; /* Write back */ CPSAR_CACHE_WRITEBACK(currBD, CPPI4_BD_LENGTH_FOR_CACHE); currBD = (Cppi4BD *)CPSAR_VIRT_2_PHYS((Uint32)currBD); //DDA_printf("%s: Got NULL CurrBD for cnt = %d \n",__FUNCTION__, cnt); PAL_cppi4RxFreeBDPush(rxCppi->cppi4RxChHnd, (Uint32 *)currBD, NULL); currBD = (Cppi4BD *)(CPSAR_PHYS_2_VIRT(currBD)); currBD++; } /**** Start of Critical Section ****/ PAL_osProtectEntry(PAL_OSPROTECT_INTERRUPT, &lockKey); /* Update the memory list while protected */ if (rxCppi->BdMemList == NULL) { rxCppi->BdMemList = MemChunk; } else { MemChunk->ptrNext = (struct Cppi4BdMemChunk *)rxCppi->BdMemList; rxCppi->BdMemList = MemChunk; } /**** End of Critical Section ****/ PAL_osProtectExit(PAL_OSPROTECT_INTERRUPT,lockKey); } //End AV_FIX_BD /* Open the channel in the CPPI4 PAL */ retCode = PAL_cppi4EnableRxChannel(rxCppi->cppi4RxChHnd, NULL); if(retCode != PAL_SOK) { DDA_printf("\nERROR:%s: Error %08X from CPPI4 PAL EnableRxChannel()", __FUNCTION__, retCode); return (retCode); } /* If this is the first ch to use this rxQueue, enable the interrupt */ if (hDDC->rxIntLineCount[rxQueue] == 1) { hDDC->rxIntLine[rxQueue] = rxQueue + CPPI4_MIN_RX_INT_LINE; retCode = PAL_cppi4EnableRxIntr(rxCppi->cppi4RxChHnd, NULL); if(retCode != PAL_SOK) { DDA_printf("\nERROR:cpmacEnableChannel: Error %08X from CPPI4 PAL EnableRxIntr()", retCode); return (retCode); } } /* Mark channel open */ hDDC->rxIsOpen |= channel_mask; rxCppi->chInfo.chState = DDC_NET_CH_OPENED; } LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarEnableChannel:%d: Ch=%d, Direction=%s", hDDC->instId, channel, ((direction==DDC_NET_CH_DIR_TX) ? "TX" : "RX")); return (CPSAR_SUCCESS); } /** * cpsarInitTxChannel * - Allocates memory for TX Ch Control structure, Buffer descriptors * - Initialize the above data structures as per channel configuration * - Chain the TX BD list ready to be given to hardware * * \note 1. "chOpenArgs" not used in this implementation * 2. This function assumes that the channel number passed is valid and * the hDDC->txCppi[channel] pointer is NULL. This function will not * do any error check on these parameters to avoid duplicate error * checks (done in caller function). */ static int cpsarInitTxChannel(CpsarDDCObj *hDDC, CpsarChInfo *chInfo, void * chOpenArgs) { int retCode; unsigned int cnt; Cppi4BD *currBD; CpsarTxCppiCh *txCppi = &hDDC->txCppi[chInfo->chNum]; unsigned int channel_mask = (1 << chInfo->chNum); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarInitTxChannel:%d: Ch=%d", hDDC->instId, chInfo->chNum); /* Populate channel info */ txCppi->chInfo.chState = DDC_NET_CH_INITIALIZED; hDDC->txTeardownPending &= ~channel_mask; txCppi->allocSize = sizeof(Cppi4BD) * chInfo->numTxBD; retCode = PAL_osMemAlloc(0, txCppi->allocSize, CPPI4_BD_ALIGN, (void * *)&txCppi->bdMem); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarInitTxChannel:%d: Failed to allocated %d bytes for BD pool memory for ch %d", hDDC->instId, txCppi->allocSize, chInfo->chNum); return (retCode); } /* Set memory to 0 */ PAL_osMemSet(txCppi->bdMem, 0, txCppi->allocSize); /* Initialize the BD linked list */ currBD = (Cppi4BD *)txCppi->bdMem; txCppi->bdPoolHead = 0; DDA_printf("%s: Allocating %d buffers at currBD = 0x%p \n", __FUNCTION__, chInfo->numTxBD, currBD); DDA_printf("%s: TX Service Max is set to %d \n",__FUNCTION__, chInfo->TxServiceMax); for (cnt = 0; cnt < chInfo->numTxBD; cnt++) { currBD->nextBDPtr = (void *) txCppi->bdPoolHead; txCppi->bdPoolHead = currBD; currBD++; } txCppi->savedBD = NULL; hDDC->txIsCreated |= channel_mask; LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarInitTxChannel:%d: Ch=%d", hDDC->instId, chInfo->chNum); return (CPSAR_SUCCESS); } /** * cpsarInitRxChannel * - Allocates memory for RX Ch structure and other internal structs * - prepares the rx packet list * * \note 1. "chOpenArgs" unused * 2. This function assumes that the channel number passed is valid and * the hDDC->rxCppi pointer is NULL. This function will not do any * error check on these parameters to avoid duplicate error checks * (done in caller function). */ static int cpsarInitRxChannel(CpsarDDCObj *hDDC, CpsarChInfo *chInfo, void * chOpenArgs) { int retCode; CpsarRxCppiCh *rxCppi = &hDDC->rxCppi[chInfo->chNum]; unsigned int channel_mask = (1 <chNum); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarInitRxChannel:%d: Ch=%d", hDDC->instId, chInfo->chNum); /* Populate channel info */ rxCppi->chInfo.chState = DDC_NET_CH_INITIALIZED; hDDC->rxTeardownPending &= ~channel_mask; /* rxBufferPtr */ retCode = PAL_osMemAlloc(0, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int)), 4, (void * *)&rxCppi->rxBufferPtr); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarInitRxChannel:%d: Failed to allocate memory for rxBufferPtr %d", hDDC->instId, chInfo->chNum); goto allocRxBufferPtrFail; } PAL_osMemSet(rxCppi->rxBufferPtr, 0, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); /* rxDataToken */ retCode = PAL_osMemAlloc(0, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int)), 4, (void * *)&rxCppi->rxDataToken); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarInitRxChannel:%d: Failed to allocate memory for rxDataToken %d", hDDC->instId, chInfo->chNum); goto allocRxDataTokenFail; } PAL_osMemSet(rxCppi->rxDataToken, 0, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); /* Allocate memory for packet queue on a 4 byte boundry and set to 0 */ retCode = PAL_osMemAlloc(0, (chInfo->RxServiceMax * sizeof(DDC_NetPktObj)), 4, (void * *)&rxCppi->pktQueue); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarInitRxChannel:%d: Failed to allocate memory for RX packet queue %d", hDDC->instId, chInfo->chNum); goto allocPktQueueFail; } PAL_osMemSet(rxCppi->pktQueue, 0, (chInfo->RxServiceMax * sizeof(DDC_NetPktObj))); /* Allocate memory for buffer queue on a 4 byte boundry and set to 0 */ retCode = PAL_osMemAlloc(0, (chInfo->RxServiceMax * sizeof(DDC_NetBufObj) * hDDC->initCfg.rxMaxFrags), 4, (void * *)&rxCppi->bufQueue); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarInitRxChannel:%d: Failed to allocate memory for RX buffer queue %d", hDDC->instId, chInfo->chNum); goto allocBufQueueFail; } PAL_osMemSet(rxCppi->bufQueue, 0, (chInfo->RxServiceMax * sizeof(DDC_NetBufObj) * hDDC->initCfg.rxMaxFrags)); /* Build the packet-buffer structures */ { int cnt; DDC_NetPktObj *currPkt = &rxCppi->pktQueue[0]; DDC_NetBufObj *currBuf = &rxCppi->bufQueue[0]; /* Bind pkt and buffer queue data structures */ for (cnt = 0; cnt < chInfo->RxServiceMax; cnt++) { currPkt->bufList = currBuf; ++currPkt; currBuf += hDDC->initCfg.rxMaxFrags; } } rxCppi->savedBD = NULL; hDDC->rxIsCreated |= channel_mask; return (CPSAR_SUCCESS); allocBufQueueFail: /* Free pkt queue */ PAL_osMemFree(0, rxCppi->pktQueue, (chInfo->RxServiceMax * sizeof(DDC_NetPktObj))); allocPktQueueFail: /* Free rxBufferPtr */ PAL_osMemFree(0, rxCppi->rxDataToken, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); allocRxDataTokenFail: /* Free rxBufferPtr */ PAL_osMemFree(0, rxCppi->rxBufferPtr, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); allocRxBufferPtrFail: LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarInitRxChannel:%d: Ch=%d", hDDC->instId, chInfo->chNum); return (retCode); } /** * DDC_cpsarChClose * - If DDC instance is in "Opened" state, disable the channel in hardware * - Un-initialize the channel (free memory previously allocated) */ int DDC_cpsarChClose(CpsarDDCObj *hDDC, int channel, int direction, void * chCloseArgs) { int retCode; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ DDC_cpsarChClose:%d: Ch=%d, Dir=%s", hDDC->instId, channel, ((direction == DDC_NET_CH_DIR_TX) ? "TX" : "RX") ); if (direction == DDC_NET_CH_DIR_TX) { if (! hDDC->txIsOpen & channel_mask) { return (CPSAR_ERR_TX_CH_ALREADY_CLOSED); } } if (direction == DDC_NET_CH_DIR_RX) { if (! hDDC->rxIsOpen & channel_mask) { return (CPSAR_ERR_RX_CH_ALREADY_CLOSED); } } /* Disable this channel */ if (hDDC->state == DDC_OPENED) { retCode = cpsarDisableChannel(hDDC, channel, direction); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChClose:%d: Error disabling channel %d in %d direction", hDDC->instId, channel, ((direction == DDC_NET_CH_DIR_TX) ? "TX" : "RX")); return (retCode); } } /* UnInit channel */ if (direction == DDC_NET_CH_DIR_TX) { retCode = cpsarUnInitTxChannel(hDDC, channel, chCloseArgs); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChClose:%d: Error in UnInit of TX channel %d", hDDC->instId, channel); return (retCode); } } else if (direction == DDC_NET_CH_DIR_RX) { retCode = cpsarUnInitRxChannel(hDDC, channel, chCloseArgs); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChClose:%d: Error in UnInit of TX channel %d", hDDC->instId, channel); return (retCode); } } LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- DDC_cpsarChClose:%d: Ch=%d, Dir=%s", hDDC->instId, channel, ((direction == DDC_NET_CH_DIR_TX) ? "TX" : "RX") ); return (CPSAR_SUCCESS); } /** * cpsarDisableChannel * - Channel is disabled in hardware. Data transfer is finished. * * \note 1. It is assumed that the channel number passed is valid * 2. Resources for the channel will be released only when its closed */ static int cpsarDisableChannel(CpsarDDCObj *hDDC, unsigned int channel, DDC_NetChDir direction) { volatile unsigned int *pTmp; unsigned int i, retCode; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarDisableChannel:%d: Ch=%d, Direction=%s", hDDC->instId, channel, ((direction==DDC_NET_CH_DIR_TX) ? "TX" : "RX")); DDA_printf("%s: called for channel %d with dir =%d\n",__FUNCTION__, channel, direction); /* Set teardown pending flags */ if (direction == DDC_NET_CH_DIR_TX) { hDDC->txTeardownPending |= channel_mask; } else if (direction == DDC_NET_CH_DIR_RX) { hDDC->rxTeardownPending |= channel_mask; } if (direction == DDC_NET_CH_DIR_TX) { unsigned int txCompQueue; unsigned int numQueues; unsigned int queue; CpsarTxCppiCh *txCppi = &hDDC->txCppi[channel]; Cppi4BD *currBD; DDA_printf("\n%s: Called for channel %d hDDC->txTeardownPending = %d \n", __FUNCTION__, channel, hDDC->txTeardownPending); retCode = PAL_cppi4DisableTxChannel(txCppi->cppi4TxChHnd,NULL); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:%s: Error %08X from CPPI4 PAL DisableTxChannel()", __FUNCTION__, retCode); return (retCode); } //CZ no need for OAM if (channel != RESERVED_OAM_CHANNEL) //OAM { while (hDDC->txTeardownPending & channel_mask) { DDA_sleep_interruptible(100); } } DDA_printf("\n%s: Got Interrupt channel %d hDDC->txTeardownPending = %d \n", __FUNCTION__, channel, hDDC->txTeardownPending); /* There might be packets on the Tx queue that weren't sent. They need to be recycled properly. */ if (channel == 0) numQueues = 4; else numQueues = 1; for (queue=0; queue < numQueues; queue++) { int count = 0; while ((currBD = (Cppi4BD*)((Uint32)CPSAR_PHYS_2_VIRT((Cppi4BD *)PAL_cppi4TxFlush(txCppi->cppi4TxChHnd,0, NULL)))) !=(Cppi4BD*)(CPSAR_PHYS_2_VIRT(0))) { DDC_send_complete(hDDC->hDDA, (DDC_NetDataToken)&currBD->bufToken, 1, 0); DDA_printf("\n%s: Called send complete for channel %d \n", __FUNCTION__, channel); count++; } } /* Close the channel in the CPPI4 PAL */ /* @note The last parameter, if 1, tells the cppi4 NOT to write the Rx teardown register, which doesn't work properly for the SAR. Instead we must use the Rx LUT teardown register */ retCode = PAL_cppi4TxChClose(txCppi->cppi4TxChHnd, NULL); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC: cpsarDisableChannel: Error %08X from CPPI4 PAL ChClose()",retCode); return (retCode); } /* Clear PDSP TX Channel State RAM */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Tx_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Tx_State[0]; #endif for (i=0; iscratchpad_regs->PDSP_CH_RAM[channel].AAL5_Tx_VP_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Tx_VP_State[0]; #endif for (i=0; itxCppi[channel].chInfo.cppi4TxChInfo.cqIndex; hDDC->txIntLineCount[txCompQueue] -= 1; if (hDDC->txIntLineCount[txCompQueue] == 0) { volatile unsigned int *TxIntrDisEnbReg = (volatile unsigned int *)0xa3069004; unsigned int TxIntrDisEnbVal = 1 << txCompQueue; //PAL_cppi4DisableTxIntr(txCppi->cppi4TxChHnd, NULL); *TxIntrDisEnbReg = TxIntrDisEnbVal; DDA_printf("\n%s: Disabling the interrupt for q %d \n", __FUNCTION__, txCompQueue); } /* Mark channel closed */ hDDC->txIsOpen &= ~channel_mask; } else if (direction == DDC_NET_CH_DIR_RX) { unsigned int rxQueue; CpsarRxCppiCh *rxCppi = &hDDC->rxCppi[channel]; /* perform actual channel teardown in Rx LUT */ if (!(hDDC->regs->Rx_LUT_Ch_Teardown_Req & 0x80000000)) { return(CPSAR_ERR_LUT_NOT_READY); } hDDC->regs->Rx_LUT_Ch_Teardown_Req = channel; DDA_printf("\n%s: RX Ch %d closing\n", __FUNCTION__, channel); //CZ no need for OAM if (channel != RESERVED_OAM_CHANNEL) //OAM { /* Wait for the TearDown interrupt. */ while (hDDC->rxTeardownPending & channel_mask) { DDA_sleep_interruptible(100); } } /* Close the channel in the CPPI4 PAL */ DDA_printf("\n%s: RX Ch %d Teardown Interrupt occured\n", __FUNCTION__, channel); DDA_critical_on(); retCode = PAL_cppi4RxChClose(rxCppi->cppi4RxChHnd, NULL); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC: cpsarDisableChannel: Error %08X from CPPI4 PAL ChClose()",retCode); return (retCode); } /* Clear PDSP RX Channel State RAM */ #ifndef SAR_OLD pTmp = &hDDC->scratchpad_regs->PDSP_CH_RAM[channel].AAL5_Rx_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Rx_State[0]; #endif for (i=0; iscratchpad_regs->PDSP_CH_RAM[channel].AAL5_Rx_VP_State[0]; #else pTmp = &hDDC->regs->PDSP_RAM[channel].AAL5_Rx_VP_State[0]; #endif for (i=0; irxCppi[channel].chInfo.cppi4RxChInfo.rqIndex; hDDC->rxIntLineCount[rxQueue] -= 1; if (hDDC->rxIntLineCount[rxQueue] == 0) { BdMemChunk *currMemChunk; unsigned int lockKey; volatile unsigned int *RxChIntDisEnReg = (volatile unsigned int *)(0xa3069044); unsigned int RxIntrDisEnbVal = 1 << rxQueue; DDA_printf("%s: Disabling the Rx interrupt for queue %d\n",__FUNCTION__, rxQueue); //PAL_cppi4DisableRxIntr(rxCppi->cppi4RxChHnd, NULL); *RxChIntDisEnReg = RxIntrDisEnbVal; DDA_printf("\n%s: Starting to free RX BDs for queue %d", __FUNCTION__, rxQueue); /* Flush the recieve queue. */ while (((Uint32)CPSAR_PHYS_2_VIRT((Cppi4BD *)PAL_cppi4RxFreeBDFlush(rxCppi->cppi4RxChHnd,NULL)))!=0x80000000) { ; } /**** Start of Critical Section ****/ PAL_osProtectEntry(PAL_OSPROTECT_INTERRUPT, &lockKey); currMemChunk = rxCppi->BdMemList; if (currMemChunk != NULL) { while(currMemChunk) { Cppi4BD *currBD; BdMemChunk *lastMemChunk; unsigned int numBd; currBD = (Cppi4BD *)currMemChunk->bdMemPtr; numBd = currMemChunk->numBd; /* Free the Receive buffers previously allocated */ while (numBd > 0) { DDC_free_rxbuffer(hDDC->hDDA, (DDC_NetDataToken) currBD->bufToken, channel); numBd--; currBD++; } /* Free the descriptor block*/ retCode = PAL_osMemFree(0, currMemChunk->bdMemPtr,currMemChunk->bdMemSize); if (retCode != PAL_SOK) { DDA_printf("\nERROR:cppi4FreeRxBd: Failed to free memory for BD chunk"); /* do not abandon efforts to free memory, despite failure */ } /* save this chunk address for freeing */ lastMemChunk = currMemChunk; /* Move to next mem chunk */ currMemChunk = (BdMemChunk *)currMemChunk->ptrNext; /* Free the BD mem chunk structure */ PAL_osMemFree(0, lastMemChunk, sizeof(BdMemChunk)); } } /**** End of Critical Section ****/ PAL_osProtectExit(PAL_OSPROTECT_INTERRUPT,lockKey); DDA_printf("\n%s:Finished freeing RX BDs for queue %d\n", __FUNCTION__, rxQueue); } /* Mark channel open */ hDDC->rxIsOpen &= ~channel_mask; DDA_critical_off(); } LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarDisableChannel:%d: Ch=%d, Direction=%s", hDDC->instId, channel, ((direction==DDC_NET_CH_DIR_TX) ? "TX" : "RX")); return (CPSAR_SUCCESS); } /** * cpsarUnInitTxChannel * - Frees memory previously allocated for Ch Control structure, buffer * descriptors * * \note 1. "chCloseArgs" not used in this implementation * 2. This function assumes that the channel number passed is valid and * this function will not do any error check to avoid duplicate error * checks (done in caller function). */ static int cpsarUnInitTxChannel(CpsarDDCObj *hDDC, unsigned int channel, void * chCloseArgs) { int retCode; CpsarTxCppiCh *txCppi; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarUnInitTxChannel:%d: Ch=%d", hDDC->instId, channel); DDA_printf("\n cpsarUnInitTxChannel:%d: Ch=%d\n", hDDC->instId, channel); /* Check if channel structure is already de-allocated */ if(!(hDDC->txIsCreated & channel_mask)) { DDA_printf("\nERROR:DDC: cpsarUnInitTxChannel:%d: TX CPPI Channel %d structure already freed\n", hDDC->instId, channel); return (CPSAR_ERR_TX_CH_ALREADY_CLOSED); } txCppi = &hDDC->txCppi[channel]; DDA_printf("\n %s: Freeing buffers for Ch=%d\n", __FUNCTION__, channel); /* Free the buffer descriptors memory */ if (txCppi->bdMem != NULL) { retCode = PAL_osMemFree(0, txCppi->bdMem, txCppi->allocSize); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarUnInitTxChannel:%d: Failed to free memory for BD Pool for Ch %d\n", hDDC->instId, channel ); } txCppi->bdMem = NULL; } /* Clean up the TX Channel structure */ DDA_memset(txCppi, 0, sizeof(CpsarTxCppiCh)); DDA_printf("\n %s: Finished Freeing buffers for Ch=%d\n", __FUNCTION__, channel); hDDC->txIsCreated &= ~channel_mask; LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarUnInitTxChannel:%d: Ch=%d\n", hDDC->instId, channel); DDA_printf("\n %s: Finished for Ch=%d\n", __FUNCTION__, channel); return (CPSAR_SUCCESS); } /** * cpsarUnInitRxChannel * - Frees memory previously allocated in InitRxChannel * * \note 1. "chCloseArgs" not used in this implementation * 2. This function assumes that the channel number passed is valid and * this function will not do any error check to avoid duplicate error * checks (done in caller function). */ static int cpsarUnInitRxChannel(CpsarDDCObj *hDDC, unsigned int channel, void * chCloseArgs) { int retCode = PAL_SOK; CpsarRxCppiCh *rxCppi; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarUnInitRxChannel:%d: Ch=%d", hDDC->instId, channel); /* Check if channel structure is already de-allocated */ if (!hDDC->rxIsCreated & channel_mask) { DDA_printf("\nERROR %s:RX CPPI Channel %d structure already freed hDDC->rxIsCreated = %#x", channel, hDDC->rxIsCreated); return (CPSAR_ERR_RX_CH_ALREADY_CLOSED); } rxCppi = &hDDC->rxCppi[channel]; /* Free the RX buffer queue */ retCode = PAL_osMemFree(0, rxCppi->bufQueue, (rxCppi->chInfo.RxServiceMax * sizeof(DDC_NetBufObj) * hDDC->initCfg.rxMaxFrags)); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarUnInitRxChannel:%d: Failed to free RX buffer queue for Ch %d", hDDC->instId, channel ); } /* Free the RX packet queue */ retCode = PAL_osMemFree(0, rxCppi->pktQueue,(rxCppi->chInfo.RxServiceMax * sizeof(DDC_NetPktObj))); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarUnInitRxChannel:%d: Failed to free RX packet queue for Ch %d", hDDC->instId, channel ); } /* Free the rxDataToken */ retCode = PAL_osMemFree(0, rxCppi->rxDataToken, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarUnInitRxChannel:%d: Failed to free rxDataToken for Ch %d", hDDC->instId, channel ); } /* Free the rxBufferPtr */ retCode = PAL_osMemFree(0, rxCppi->rxBufferPtr, (hDDC->initCfg.rxMaxFrags * sizeof(unsigned int))); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC: cpsarUnInitRxChannel:%d: Failed to free rxBufferPtr for Ch %d", hDDC->instId, channel ); } DDA_memset(rxCppi, 0, sizeof(CpsarRxCppiCh)); hDDC->rxIsCreated &= ~channel_mask; LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- cpsarUnInitRxChannel:%d: Ch=%d", hDDC->instId, channel); return (CPSAR_SUCCESS); } /** * DDC_cpsarDeleteInstance * - delete the "instance" created via CreateInstance * * \note "param" is not used in this implementation */ int DDC_cpsarDeleteInstance (CpsarDDCObj *hDDC, void * param) { int retCode = CPSAR_SUCCESS; unsigned int instId = hDDC->initCfg.instId; LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ DDC_cpsarDeleteInstance %d", instId); /* Check instance created global variable */ if (CpsarDDCInstCreated[instId] == False) { DDA_printf("\nERROR:DDC_cpsarDeleteInstance:%d: Instance NOT created / Already deleted", instId); return (CPSAR_ERR_DEV_NOT_INSTANTIATED); } /* Update instance created global variable */ CpsarDDCInstCreated[instId] = False; CpsarDDCObject[instId] = NULL; --CpsarDDCNumInst; /* Free resources allocated */ if (hDDC != NULL) { retCode = PAL_osMemFree(0, hDDC, sizeof(CpsarDDCObj)); if (retCode != PAL_SOK) { DDA_printf("\nERROR:DDC_cpsarDeleteInstance:%d: Failed to free memory of DDC Instance Object. Error=%08X", instId, retCode); } hDDC = NULL; } LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- DDC_cpsarDeleteInstance:%d:", instId); return (retCode); } /** * DDC_cpsarChOpen * - Verify channel info (range checking etc) * - Allocate memory for the channel * - Book-keep operations for the channel - ready to be enabled in hardware * * QNum : * [7:0] = Recieve Queue Index for the RX channel. * [15:8] = TX completion Queue Index for the TX channel. * [16] = CPPI error handling. * * \note 1. If DDC instance is in "Opened" state, the channel is enabled in hw */ int DDC_cpsarChOpen(CpsarDDCObj *hDDC, CpsarChInfo *chInfo, unsigned int QNum) { int retCode; unsigned int channel_mask = (1 << chInfo->chNum); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ DDC_cpsarChOpen:%d: Ch=%d, Dir=%s", hDDC->instId, chInfo->chNum, ((chInfo->chDir == DDC_NET_CH_DIR_TX) ? "TX" : "RX") ); if (chInfo->chDir == DDC_NET_CH_DIR_TX) { if (hDDC->txIsOpen & channel_mask) { return (CPSAR_ERR_TX_CH_ALREADY_OPENED); } } if (chInfo->chDir == DDC_NET_CH_DIR_RX) { if (hDDC->rxIsOpen & channel_mask) { return (CPSAR_ERR_RX_CH_ALREADY_OPENED); } } /* If the channel state is not DDC_NET_CH_UNINITIALIZED, return error */ if (chInfo->chState != DDC_NET_CH_UNINITIALIZED) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: %s channel %d should be in DDC_NET_CH_UNINITIALIZED state", hDDC->instId, ((chInfo->chDir == DDC_NET_CH_DIR_TX) ? "TX" : "RX"), chInfo->chNum); return (CPSAR_INVALID_PARAM); } /* Init channel */ ddc_sar_init_cppi4Config(hDDC, chInfo, QNum); DDA_printf("%s: Openning channel %d \n", __FUNCTION__, chInfo->chNum); if (chInfo->chDir == DDC_NET_CH_DIR_TX) { if (chInfo->chNum >= hDDC->initCfg.numTxChannels) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: Invalid TX Channel=%d specified", hDDC->instId, chInfo->chNum); return (CPSAR_ERR_TX_CH_INVALID); } if (hDDC->txIsCreated & channel_mask) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: TX Channel %d already open", hDDC->instId, chInfo->chNum); return (CPSAR_ERR_TX_CH_ALREADY_INIT); } /* Allocate channel memory and perform other book-keep functions for the channel */ retCode = cpsarInitTxChannel(hDDC, chInfo, NULL); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: Error in initializing TX channel %d", hDDC->instId, chInfo->chNum); return (retCode); } } else if (chInfo->chDir == DDC_NET_CH_DIR_RX) { if (chInfo->chNum >= hDDC->initCfg.numRxChannels) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: Invalid RX Channel=%d specified", hDDC->instId, chInfo->chNum); return (CPSAR_ERR_RX_CH_INVALID); } if (hDDC->rxIsCreated & channel_mask) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: RX Channel %d already open", hDDC->instId, chInfo->chNum); return (CPSAR_ERR_RX_CH_ALREADY_INIT); } /* Allocate channel memory and perform other book-keep functions for the channel */ retCode = cpsarInitRxChannel(hDDC, chInfo, NULL); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: Error in initializing RX channel %d", hDDC->instId, chInfo->chNum); return (retCode); } } /* If device is opened already, enable this channel for use */ if (hDDC->state == DDC_OPENED) { retCode = cpsarEnableChannel(hDDC, chInfo->chNum, chInfo->chDir); if (retCode != CPSAR_SUCCESS) { DDA_printf("\nERROR:DDC_cpsarChOpen:%d: Error enabling channel %d in %d direction", hDDC->instId, chInfo->chNum, chInfo->chDir); return (retCode); } } else { DDA_printf("\nERROR:%s DDC not initialized as yet \n", __FUNCTION__); } LOGMSG(CPSAR_DEBUG_FUNCTION_EXIT, "\n- DDC_cpsarChOpen:%d: Ch=%d, Dir=%s", hDDC->instId, chInfo->chNum, ((chInfo->chDir == DDC_NET_CH_DIR_TX) ? "TX" : "RX") ); return (CPSAR_SUCCESS); } /************************************************************ NEED FN HEADER ************************************************************/ int ddc_sar_init_config_params(CpsarDDCObj *hDDC, int useLB) { Cppi4InitConfig *iCfg = &hDDC->initCfg.cppi4InitCfg; CpsarInitConfig *initCfg = &hDDC->initCfg; //AV_SM : The following are the only fields that need to be initialized now. //bk Fehler in TI Code die Richtige Werte sind im RGDK unter include/asm/mach-avalanche/yamuna/yamuna.h iCfg->qmRegs_Addr = 0xA3068000; /**< Queue manager region address */ iCfg->dmaRegs_Addr = 0xA300A000; /**< CPPI 4.0 DMA region address */ //iCfg->qmRegs_Addr = 0xA300A000; /**< Queue manager region address */ //iCfg->dmaRegs_Addr = 0xA3068000; /**< CPPI 4.0 DMA region address */ //end bk iCfg->resetLine = 9; /**< NWSS Reset Line Number */ initCfg->baseAddress = 0xa3000000; initCfg->scratchpadAddress = 0xa3130000; initCfg->uniNni = 0; //iCfg->cpsarBusFrequency = GetPbusFreq(); initCfg->cpsarBusFrequency = 120000000; //PAL_sysClkcGetFreq (CLKC_VBUS); initCfg->cpuFrequency = shim_osGetCpuFrequency(); //GetCpuFreq(); initCfg->loopFirmware = &SarPdspLoopFirmware[0]; initCfg->firmware = &SarPdspFirmware[0]; initCfg->loopFirmwareSize = sizeof(SarPdspLoopFirmware); initCfg->firmwareSize = sizeof(SarPdspFirmware); //AV_SM : TODO The following need to be properly initialized and not use absolute values. initCfg->instId = 0; initCfg->numTxChannels = CPSAR_MAX_TX_CHANNELS; initCfg->numRxChannels = CPSAR_MAX_RX_CHANNELS; initCfg->oamLbTimeout = 5000; initCfg->uniNni = 0; initCfg->oamMode = 1; //firmware mode; initCfg->deviceCPID[0] = 0xffffffff; initCfg->deviceCPID[1] = 0xffffffff; initCfg->deviceCPID[2] = 0xffffffff; initCfg->deviceCPID[3] = 0xffffffff; initCfg->lbSourceLLID[0] = 0xffffffff; initCfg->lbSourceLLID[1] = 0xffffffff; initCfg->lbSourceLLID[2] = 0xffffffff; initCfg->lbSourceLLID[3] = 0xffffffff; /* If we need to use Loopback firmware */ if(!useLB) initCfg->useLoopFirmware = 0; else initCfg->useLoopFirmware = 1; //AV_SM : TODO add support for multiple frags. initCfg->rxMaxFrags = 1; //MAX_FRAGS return 0; } /*Note: Error checking not done in here. * Mode : * 0 = AAL5, 1 = PTI based NULL, * 2 = ATM OAM, 3 = ATM Trans, * 4 = EFM, 7 = Ethernet. * * QNum : * [7:0] = Recieve Queue Index for the RX channel. * [15:8] = TX completion Queue Index for the TX channel. * [16] = CPPI error handling. */ static int ddc_sar_init_cppi4Config(CpsarDDCObj *hDDC, CpsarChInfo *chInfo, unsigned int QNum) { int ch = chInfo->chNum; int mode = chInfo->PktType; Cppi4TxChInfo *cppi4txChCfg = &hDDC->txCppi[ch].chInfo.cppi4TxChInfo; Cppi4RxChInfo *cppi4rxChCfg = &hDDC->rxCppi[ch].chInfo.cppi4RxChInfo; unsigned int tq_num = ((QNum >> TX_Q_SHIFT) & 0xFF); unsigned int rq_num = ((QNum >> RX_Q_SHIFT) & 0xFF); unsigned int bErrProc = ((QNum >> ERR_PROC_SHIFT) & 0x1); hDDC->txCppi[ch].chInfo = *chInfo; hDDC->rxCppi[ch].chInfo = *chInfo; hDDC->txCppi[ch].chInfo.chState = DDC_NET_CH_UNINITIALIZED; DDA_printf("%s: Got ch %d chInfo is at 0x%p \n", __FUNCTION__, ch, cppi4rxChCfg); cppi4txChCfg->descCopyByteCount = 0; cppi4txChCfg->cqIndex = tq_num; /* Using Tx complete queue 2 for now. */ cppi4txChCfg->pktType = mode; /* AV: Testing with different free buffer. */ cppi4rxChCfg->fbqIndex[3] = tq_num; cppi4rxChCfg->fbqIndex[2] = tq_num; cppi4rxChCfg->fbqIndex[1] = tq_num; cppi4rxChCfg->fbqIndex[0] = tq_num; cppi4rxChCfg->errHandling = bErrProc; /* 0 = Port-drop */ cppi4rxChCfg->sopOffset = 0; cppi4rxChCfg->rqIndex = rq_num; /* Using rq 2 for now. CPPI now takes care of the conversion. */ #ifdef EB cppi4txChCfg->chInfo.endian = 1; /* 0 = little 1 = big */ #else cppi4txChCfg->chInfo.endian = 0; /* 0 = little 1 = big */ #endif cppi4txChCfg->chInfo.chMode = 0; /* 0 = host mode 1= embedded mode */ cppi4rxChCfg->chInfo.chNum = ch; cppi4txChCfg->chInfo.chNum = ch; #ifdef EB cppi4rxChCfg->chInfo.endian = 1; /* 0 = little 1 = big */ #else cppi4rxChCfg->chInfo.endian = 0; /* 0 = little 1 = big */ #endif cppi4rxChCfg->chInfo.chMode = 0; /* 0 = host mode 1= embedded mode */ DDA_printf("\n %s: cppi4rxChCfg->chInfo.chNum = %d tq_num = %d rq_num = %d \n", __FUNCTION__, hDDC->rxCppi[ch].chInfo.cppi4RxChInfo.chInfo.chNum, tq_num, rq_num); return (CPSAR_SUCCESS); } /* Debug functions */ #ifdef CPSAR_DDC_GETSTATS /************************************************************ NEED FN HEADER ************************************************************/ /* DDC specific debug functions */ void ddc_cpsarDDCStats(CpsarDDCObj *hDDC, unsigned char ch) { CpsarRxCppiCh *rxCppi; CpsarTxCppiCh *txCppi; int instId = hDDC->instId; unsigned int txQueue; unsigned int rxQueue; DDA_printf("\nSAR Stats for channel %d \n", ch); if (hDDC == NULL) { DDA_printf("\ncpsarDumpRxStat: Invalid DDC handle for instance id %d.", instId); return; } rxCppi = &hDDC->rxCppi[ch]; txCppi = &hDDC->txCppi[ch]; DDA_printf("\nQosType= %d", txCppi->chInfo.TxVc_QosType); DDA_printf("\nPriority = %d", txCppi->chInfo.Priority); DDA_printf("\nCellRate = %d", txCppi->chInfo.TxVc_CellRate); DDA_printf("\nMbs = %d", txCppi->chInfo.TxVc_Mbs); DDA_printf("\nPcr = %d", txCppi->chInfo.TxVc_Pcr); txQueue = txCppi->chInfo.cppi4TxChInfo.cqIndex; rxQueue = rxCppi->chInfo.cppi4RxChInfo.rqIndex; DDA_printf("\nCPSAR Instance %d , Ch %d Statistics", instId, ch); if (hDDC->txTeardownPending & ch) DDA_printf("\nTX Teardown pending ..."); else { DDA_printf("\n"); DDA_printf("\nTX Int Count = %u", hDDC->txIntCount[txQueue]); DDA_printf("\nTX Int with no active pkts = %u", hDDC->txEmptyIntCount[txQueue]); DDA_printf("\nTX Out of BD's = %u", txCppi->outOfTxBD); } if (hDDC->rxTeardownPending & ch) DDA_printf("\nRX Teardown pending ..."); else { DDA_printf("\n"); DDA_printf("\nRX Int Count = %u", hDDC->rxIntCount[rxQueue]); DDA_printf("\nRX Int with no active pkts = %u", hDDC->rxEmptyIntCount[rxQueue]); DDA_printf("\nRX Out of Buffers = %u", rxCppi->outOfRxBuffers); DDA_printf("\nRX CRC Errors = %u", rxCppi->rxCrcErrors); DDA_printf("\nRX Length Errors = %u", rxCppi->rxLengthErrors); DDA_printf("\nRX Abort Errors = %u", rxCppi->rxAbortErrors); DDA_printf("\nRX Recycle Multi BDs = %u", rxCppi->rxMultiBDs); } DDA_printf("\n"); } #endif /************************************************************ NEED FN HEADER ************************************************************/ int cpsarFlushTxChannel(CpsarDDCObj *hDDC, unsigned int channel, void * chCloseArgs) { CpsarTxCppiCh *txCppi; Cppi4BD *currBD; unsigned int queue, numQueues; unsigned int channel_mask = (1 << channel); LOGMSG(CPSAR_DEBUG_FUNCTION_ENTRY, "\n+ cpsarUnInitTxChannel:%d: Ch=%d", hDDC->instId, channel); /* Check if channel structure is closed */ if(!(hDDC->txIsCreated & channel_mask)) { DDA_printf("\nERROR:%s:TX CPPI Channel %d structure already freed", __FUNCTION__, channel); return (CPSAR_ERR_TX_CH_ALREADY_CLOSED); } txCppi = &hDDC->txCppi[channel]; /* There might be packets on the Tx queue that weren't sent. They need to be recycled properly. */ if (channel == 0) numQueues = 4; else numQueues = 1; for (queue=0; queue < numQueues; queue++) { int count=0; //AV_SM_CPPI while ( (currBD = (Cppi4BD*)((Uint32)CPSAR_PHYS_2_VIRT((Cppi4BD *)PAL_cppi4TxFlush(txCppi->cppi4TxChHnd,queue, NULL)))) !=(Cppi4BD*)0x80000000) { DDC_send_complete(hDDC->hDDA, (DDC_NetDataToken)&currBD->bufToken, 1, 0); count++; } } return (CPSAR_SUCCESS); } /*** OAM ping support ***/ /** * @ingroup CPSAR_Functions * * cpsarOamLoopbackConfig * This function is used to enable OAM loopback functions for a particular * channel. The channel (embedded within OamConfig - see below) must have been * configured for firmware OAM (not host OAM) for these configurations to take * effect. Only one loopback function can be enabled at a time. * * The LLID is inserted into to the OAM cell's LLID field, and it specifies the * LLID of the connection point in the network where the generated loopback * cell should be turned around. The LLID is composed of 4 32-bit words, and * this function expects the caller to pass an array of 4 words in the LLID * field. The CorrelationTag is a 32-bit word that the PDSP uses to correlate * loopback commands with loopback responses. It should simply be changed for * each call, and there is no restriction on the value used for CorrelationTag. * * The usage of the OamConfig parameter is described through the table below. * To initiate firmware OAM, set one of the bits corresponding to the * various loopback OAM functions. Note that only one loopback source may be * commanded at a time. * * This function may only be called after the module has been opened. * * Acronyms: * e2e - end to end, seg - segment, LB - loopback * * @par Bit: Function: Description * - 31:16: Reserved: * - 15: F4 LB Source seg: 0 - no action, 1 - configure (Note 1) * - 14: F4 LB Source seg: 0 - no action, 1 - configure (Note 1) * - 13: F4 LB Source e2e: 0 - no action, 1 - configure (Note 1) * - 12: F4 LB Source e2e: 0 - no action, 1 - configure (Note 1) * - 11:8: Reserved: * - 7:0: Channel: AAL5/AAL2 VC/VP channel (Note 2) * * * Note 1: Only one LB function may be enabled at one time. Once enabled, * the PDSP will time out after 5 seconds. The host must wait until * it has received the result of the current LB request before * initiating a new request.
* Note 2: This must specify the VC channel for F5 functions, and the VP * channel for F4 functions. * * @param hDDC DDC module handle * @param OamConfig A 32-bit integer field defined above. * @param LLID Loopback Location Identifier (passed as 4 word array). * Must be configured in big endian format. * @param CorrelationTag 32-bit tag correlates loopback commands with loopback * responses. Must be configured in big endian format. * @return CPSAR_SUCCESS (ok).
* Possible Error Codes:
* CPSAR_ERR_DEV_NOT_OPEN
*/ PAL_Result cpsarOamLoopbackConfig(CpsarDDCObj *hDDC, Uint32 OamConfig, Uint32 *LLID, Uint32 CorrelationTag) { volatile Uint32 *tmp; //if (hDDC->ddcObj.state == DDC_OPENED) if (hDDC->state == DDC_OPENED) { /* test to see if this is a loopback command */ if (OamConfig & 0xf000) { /* write the OAM correlation tag (GPR 1) */ hDDC->regs->Host_Mailbox[1] = CorrelationTag; /* write the LLID */ tmp = &hDDC->scratchpad_regs->PDSP_OAM_RAM.OAM_Config[4]; //printk("tmp value = %08x\n", (unsigned int) tmp); /*tmp = &hDDC->regs->PDSP_RAM[3].PDSP_General_Use[8];*/ *tmp++ = LLID[0]; *tmp++ = LLID[1]; *tmp++ = LLID[2]; *tmp = LLID[3]; /* GPR 0 */ hDDC->regs->Host_Mailbox[0] = OamConfig; //printk("addr2=%08x\n", (unsigned int) &(hDDC->regs->Host_Mailbox[0])); } } else return (CPSAR_ERR_DEV_NOT_OPEN); return (CPSAR_SUCCESS); }