/****************************************************************************************
 *   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; i<PDSP_STATE_RAM_SIZE; i++)
    *pTmp++ = 0;

  /* Configure Oam Mode */
  for (i=0; i<CPSAR_MAX_RX_CHANNELS; i++)
  #ifndef SAR_OLD
    hDDC->scratchpad_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;i<NumOfEntries;i++)
    (*((unsigned int *) (IRamAddress+(i*4))))=FirmwarePtr[i];

  /* Check code */
  for(i=8;i<NumOfEntries;i++)
    {
      iTmp=(*((unsigned int *) (IRamAddress+(i*4))));
      if (iTmp != FirmwarePtr[i])
    {
          return(CPSAR_ERR_PDSP_LOAD_FAIL);
    }
    }

  return(CPSAR_SUCCESS);
}

/**
 *  cpsarOamRateConfig
 *
 *  This function configures the rate at which the OAM timer scheduler
 *  channels will be scheduled.  The value of OamRate is the number of
 *  clock ticks between cell transmissions (if OAM function is sourcing
 *  cells), or the number of clock ticks between events or absence of events
 *  (if OAM function is sinking cells).  The value of i indicates
 *  which OAM function to apply the rate to.  A list is given below.
 *
 *  @par Oam Function Values
 *  - 0  : Loopback source
 *  - 1  : F4 CC source
 *  - 2  : F5 CC source
 *  - 3  : F4 CC sink
 *  - 4  : F5 CC sink
 *  - 5  : F4 TX AIS source
 *  - 6  : F5 TX AIS source
 *  - 7  : F4 RX RDI source
 *  - 8  : F5 RX RDI source
 *  - 9  : F4 AIS monitor
 *  - 10 : F5 AIS monitor
 *
 *  The following is information on how to calculate the OAM rate.  There
 *  is only one OAM timer that is shared among all channels.  Therefore, if
 *  you wanted an OAM source function (ex. F4 CC source) to generate 1 cell/sec
 *  across 8 channels, you would need to configure the OAM timer to schedule 8
 *  cells/sec.  In addition, the credits are shared between segment and end-to-end
 *  type OAM cells, so if you were sending both types of cells, you would
 *  need to configure the OAM timer for 16 cells/sec.  However, the clock
 *  rate must be specified in clock ticks between events.  Using an example
 *  clock rate of 125 MHz, the rate in clock ticks can be calculated by
 *  dividing 125 Mhz by 16 cells/sec.  The results is 7812500 ticks.  Thus,
 *  every 7812500 clock cycles, an OAM cell will be generated for the F4 CC
 *  Source function.
 */
static void cpsarOamRateConfig(CpsarDDCObj *hDDC)
{
  unsigned int OamRate, Freq = hDDC->initCfg.cpsarBusFrequency, i;

  /* Configure OAM Timer State Block */
  for (i=0; i<NUM_OAM_RATES; i++)
    {
      switch(i)
        {
    case 0:  OamRate = ((Freq/1000)*hDDC->initCfg.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 <<chInfo->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; i<NUM_PDSP_AAL5_TX_STATE_WORDS; i++)
        *pTmp++ = 0;

     #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
      for (i=0; i<NUM_PDSP_AAL5_TX_VP_STATE_WORDS; i++)
        *pTmp++ = 0;

      txCompQueue = hDDC->txCppi[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; i<NUM_PDSP_AAL5_RX_STATE_WORDS; i++)
        *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
      for (i=0; i<NUM_PDSP_AAL5_RX_VP_STATE_WORDS; i++)
        *pTmp++ = 0;

      rxQueue = hDDC->rxCppi[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. <BR>
 *  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). <BR>
 *           Possible Error Codes: <BR>
 *           CPSAR_ERR_DEV_NOT_OPEN <BR>
 */
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);
}
