/*
 * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

/**=========================================================================
  
  @file  wlan_qct_dxe.c
  
  @brief 
               
   This file contains the external API exposed by the wlan data transfer abstraction layer module.
========================================================================*/

/*===========================================================================

                      EDIT HISTORY FOR FILE


  This section contains comments describing changes made to the module.
  Notice that changes are listed in reverse chronological order.


  $Header:$ $DateTime: $ $Author: $


when           who        what, where, why
--------    ---         ----------------------------------------------------------
08/03/10    schang      Created module.

===========================================================================*/

/*===========================================================================

                          INCLUDE FILES FOR MODULE

===========================================================================*/

/*----------------------------------------------------------------------------
 * Include Files
 * -------------------------------------------------------------------------*/
#include "wlan_qct_dxe.h"
#include "wlan_qct_dxe_i.h"
#include "wlan_qct_pal_device.h"
#include "vos_api.h"

/*----------------------------------------------------------------------------
 * Local Definitions
 * -------------------------------------------------------------------------*/
//#define WLANDXE_DEBUG_CH_INFO_DUMP

/* Temporary configuration defines
 * Have to find out permanent solution */
#define T_WLANDXE_MAX_DESCRIPTOR_COUNT     40
#define T_WLANDXE_MAX_FRAME_SIZE           2000
#define T_WLANDXE_TX_INT_ENABLE_FCOUNT     1
#define T_WLANDXE_MEMDUMP_BYTE_PER_LINE    16
#define T_WLANDXE_MAX_RX_PACKET_WAIT       6000
#define T_WLANDXE_SSR_TIMEOUT              5000
#define T_WLANDXE_PERIODIC_HEALTH_M_TIME   2500
#define T_WLANDXE_MAX_HW_ACCESS_WAIT       2000
#define WLANDXE_MAX_REAPED_RX_FRAMES       512

#define WLANPAL_RX_INTERRUPT_PRO_MASK      0x20
#define WLANDXE_RX_INTERRUPT_PRO_UNMASK    0x5F

/* 1msec busy wait in case CSR is not valid */
#define WLANDXE_CSR_NEXT_READ_WAIT         1000
/* CSR max retry count */
#define WLANDXE_CSR_MAX_READ_COUNT         30

/* DXETRACE max records count */
#define MAX_DXE_TRACE_RECORDS              512
#define INVALID_TRACE_ADDR                 0xffffffff

/* This is temporary fot the compile
 * WDI will release official version
 * This must be removed */
#define WDI_GET_PAL_CTX()                  NULL

#define TRACE_WLANDXE_VAR_ENABLE           1
#define TRACE_WLANDXE_VAR_DISABLE          0
/*-------------------------------------------------------------------------
  *  Local Varables
  *-------------------------------------------------------------------------*/
/* This is temp, someone have to allocate for me, and must be part of global context */
static WLANDXE_CtrlBlkType    *tempDxeCtrlBlk;
static char                   *channelType[WDTS_CHANNEL_MAX] =
   {
      "TX_LOW_PRI",
      "TX_HIGH_PRI",
      "RX_LOW_PRI",
      "RX_HIGH_PRI",
      "RX_LOGS",
      "RX_FW_LOGS",
   };
static  wpt_packet               *rx_reaped_buf[WLANDXE_MAX_REAPED_RX_FRAMES];
static WLANDXE_EnvInformation    dxeEnvBlk;
static dxeTraceData              gdxeTraceData;
static dxeTraceRecord            gdxeTraceTbl[MAX_DXE_TRACE_RECORDS];
static spinlock_t                dtraceLock;

/*-------------------------------------------------------------------------
  *  External Function Proto Type
  *-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------
  *  Local Function Proto Type
  *-------------------------------------------------------------------------*/
static wpt_status dxeRXFrameSingleBufferAlloc
(
   WLANDXE_CtrlBlkType      *dxeCtxt,
   WLANDXE_ChannelCBType    *channelEntry,
   WLANDXE_DescCtrlBlkType  *currentCtrlBlock
);

static wpt_status dxeNotifySmsm
(
  wpt_boolean kickDxe,
  wpt_boolean ringEmpty
);

static void dxeStartSSRTimer
(
  WLANDXE_CtrlBlkType     *dxeCtxt
);

static wpt_status dxeTXCleanup
(
   WLANDXE_CtrlBlkType     *hostCtxt
);

static void dxeTrace
(
  v_U8_t chan, v_U8_t code, v_U32_t data
);

/*-------------------------------------------------------------------------
  *  Local Function
  *-------------------------------------------------------------------------*/
/*==========================================================================
  @  Function Name 
      dxeChannelMonitor

  @  Description 

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelMonitor
(
   char                    *monitorDescription,
   WLANDXE_ChannelCBType   *channelEntry,
   wpt_log_data_stall_channel_type *channelLog
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;

   if((NULL == monitorDescription) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "INVALID Input ARG");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if(channelEntry->channelType >= WDTS_CHANNEL_MAX)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "INVALID Channel type");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   wpalTrace(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
             "%11s : HCBO %d, HCBDP 0x%x, HCBDC 0x%x,",
             channelType[channelEntry->channelType],
             channelEntry->headCtrlBlk->ctrlBlkOrder,
             channelEntry->headCtrlBlk->linkedDescPhyAddr,
             channelEntry->headCtrlBlk->linkedDesc->descCtrl.ctrl);
   wpalTrace(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
             "%11s : TCBO %d, TCBDP 0x%x, TCBDC 0x%x",
             channelType[channelEntry->channelType],
             channelEntry->tailCtrlBlk->ctrlBlkOrder,
             channelEntry->tailCtrlBlk->linkedDescPhyAddr,
             channelEntry->tailCtrlBlk->linkedDesc->descCtrl.ctrl);
   wpalTrace(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
             "%11s : FDC %d, RDC %d, TFC %d",
             channelType[channelEntry->channelType],
             channelEntry->numFreeDesc,
             channelEntry->numRsvdDesc,
             channelEntry->numTotalFrame);

   if(channelLog)
   {
      channelLog->numDesc       = channelEntry->numDesc;
      channelLog->numFreeDesc   = channelEntry->numFreeDesc;
      channelLog->numRsvdDesc   = channelEntry->numRsvdDesc;
      channelLog->headDescOrder = channelEntry->headCtrlBlk->ctrlBlkOrder;
      channelLog->tailDescOrder = channelEntry->tailCtrlBlk->ctrlBlkOrder;
   }

   return status;
}

#ifdef WLANDXE_DEBUG_MEMORY_DUMP
/*==========================================================================
  @  Function Name 
      dxeMemoryDump

  @  Description 

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeMemoryDump
(
   wpt_uint8    *dumpPointer,
   wpt_uint32    dumpSize,
   char         *dumpTarget
)
{
   wpt_status                status      = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                numBytes    = 0;
   wpt_uint32                idx;

   if((NULL == dumpPointer) ||
      (NULL == dumpTarget))
   {
      return status;
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Location 0x%x, Size %d", dumpTarget, dumpPointer, dumpSize);

   numBytes = dumpSize % T_WLANDXE_MEMDUMP_BYTE_PER_LINE;
   for(idx = 0; idx < dumpSize; idx++)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
               "0x%2x ", dumpPointer[idx]);
      if(0 == ((idx + 1) % T_WLANDXE_MEMDUMP_BYTE_PER_LINE))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "\n");
      }
   }
   if(0 != numBytes)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW, "\n");
   }
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");

   return status;
}
#endif /* WLANDXE_DEBUG_MEMORY_DUMP */

/*==========================================================================
  @  Function Name 
      dxeDescriptorDump

  @  Description 

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
wpt_status dxeDescriptorDump
(
   WLANDXE_ChannelCBType   *channelEntry,
   WLANDXE_DescType        *targetDesc,
   wpt_uint32               fragmentOrder
)
{
   wpt_status                status      = eWLAN_PAL_STATUS_SUCCESS;


   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "Descriptor Dump for channel %s, %d / %d fragment",
                   channelType[channelEntry->channelType],
                   fragmentOrder + 1,
                   channelEntry->numFragmentCurrentChain);

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "CTRL WORD 0x%x, TransferSize %d",
                   WLANDXE_U32_SWAP_ENDIAN(targetDesc->descCtrl.ctrl),
            WLANDXE_U32_SWAP_ENDIAN(targetDesc->xfrSize));
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "SRC ADD 0x%x, DST ADD 0x%x, NEXT DESC 0x%x",
                   WLANDXE_U32_SWAP_ENDIAN(targetDesc->dxedesc.dxe_short_desc.srcMemAddrL),
                   WLANDXE_U32_SWAP_ENDIAN(targetDesc->dxedesc.dxe_short_desc.dstMemAddrL),
                   WLANDXE_U32_SWAP_ENDIAN(targetDesc->dxedesc.dxe_short_desc.phyNextL));
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");

   return status;
}

/*==========================================================================
  @  Function Name 
      dxeChannelRegisterDump

  @  Description 

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
wpt_status dxeChannelRegisterDump
(
   WLANDXE_ChannelCBType   *channelEntry,
   char                    *dumpTarget,
   wpt_log_data_stall_channel_type *channelLog
)
{
   wpt_status   status      = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32   chStatusReg, chControlReg, chDescReg, chLDescReg;

   /* Whatever RIVA power condition try to wakeup RIVA through SMSM
    * This will not simply wakeup RIVA
    * Just incase TX not wanted stuck, Trigger TX again */
   dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
   dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
   wpalSleep(10);

   if(channelEntry->channelType >= WDTS_CHANNEL_MAX)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "INVALID Channel type");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   wpalReadRegister(channelEntry->channelRegister.chDXEDesclRegAddr, &chDescReg);
   wpalReadRegister(channelEntry->channelRegister.chDXELstDesclRegAddr, &chLDescReg);
   wpalReadRegister(channelEntry->channelRegister.chDXECtrlRegAddr, &chControlReg);
   wpalReadRegister(channelEntry->channelRegister.chDXEStatusRegAddr, &chStatusReg);

   wpalTrace(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
             "%11s : CCR 0x%x, CSR 0x%x, CDR 0x%x, CLDR 0x%x",
             channelType[channelEntry->channelType],
             chControlReg, chStatusReg, chDescReg, chLDescReg);

   if(channelLog)
   {
      channelLog->ctrlRegVal = chControlReg;
      channelLog->statRegVal = chStatusReg;
   }

   return status;
}

/*==========================================================================
  @  Function Name 
      dxeChannelAllDescDump

  @  Description 
      Dump all DXE descriptors within assigned channe;

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry

  @  Return
      NONE

===========================================================================*/
void dxeChannelAllDescDump
(
   WLANDXE_ChannelCBType   *channelEntry,
   WDTS_ChannelType         channel,
   wpt_log_data_stall_channel_type *channelLog
)
{
   wpt_uint32               channelLoop;
   WLANDXE_DescCtrlBlkType *targetCtrlBlk;
   wpt_uint32               previousCtrlValue = 0;
   wpt_uint32               previousCtrlValid = 0;
   wpt_uint32               currentCtrlValid = 0;
   wpt_uint32               valDescCount = 0;
   wpt_uint32               invalDescCount = 0;

   targetCtrlBlk = channelEntry->headCtrlBlk;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "%11s : %d descriptor chains, head desc ctrl 0x%x",
            channelType[channelEntry->channelType],
            channelEntry->numDesc,
            targetCtrlBlk->linkedDesc->descCtrl.ctrl);
   previousCtrlValue = targetCtrlBlk->linkedDesc->descCtrl.ctrl;

   if((WDTS_CHANNEL_RX_LOW_PRI == channel) ||
      (WDTS_CHANNEL_RX_HIGH_PRI == channel)||
      (WDTS_CHANNEL_RX_LOG == channel))
   {
      for(channelLoop = 0; channelLoop < channelEntry->numDesc; channelLoop++)
      {
         if(previousCtrlValue != targetCtrlBlk->linkedDesc->descCtrl.ctrl)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%5d : 0x%x", targetCtrlBlk->ctrlBlkOrder,
                     targetCtrlBlk->linkedDesc->descCtrl.ctrl);
         }
         if(targetCtrlBlk->linkedDesc->descCtrl.ctrl & WLANDXE_DESC_CTRL_VALID)
         {
            valDescCount++;
         }
         else
         {
            invalDescCount++;
         }
         previousCtrlValue = targetCtrlBlk->linkedDesc->descCtrl.ctrl;
         targetCtrlBlk = (WLANDXE_DescCtrlBlkType *)targetCtrlBlk->nextCtrlBlk;
      }
   }
   else
   {
      /* Head Descriptor is valid or not */
      previousCtrlValid = targetCtrlBlk->linkedDesc->descCtrl.ctrl & WLANDXE_DESC_CTRL_VALID;
      targetCtrlBlk = (WLANDXE_DescCtrlBlkType *)targetCtrlBlk->nextCtrlBlk;
      for(channelLoop = 0; channelLoop < channelEntry->numDesc; channelLoop++)
      {
         currentCtrlValid = targetCtrlBlk->linkedDesc->descCtrl.ctrl & WLANDXE_DESC_CTRL_VALID;
         if(currentCtrlValid)
         {
            valDescCount++;
         }
         else
         {
            invalDescCount++;
         }
         if(currentCtrlValid != previousCtrlValid)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%5d : 0x%x", targetCtrlBlk->ctrlBlkOrder,
                     targetCtrlBlk->linkedDesc->descCtrl.ctrl);
         }
         previousCtrlValid = currentCtrlValid;
         targetCtrlBlk = (WLANDXE_DescCtrlBlkType *)targetCtrlBlk->nextCtrlBlk;
      }
   }

   if(channelLog)
   {
      channelLog->numValDesc   = valDescCount;
      channelLog->numInvalDesc = invalDescCount;
   }

   return;
}

/*==========================================================================
  @  Function Name
      dxeErrHandler

  @  Description
      Dump channel information for which Error interrupt has occured and
      try to recover from the Error

  @  Parameters
      WLANDXE_ChannelCBType  *channelCb

  @  Return
      wpt_status: eWLAN_PAL_STATUS_SUCCESS if recovery is possible and
                  successful
                  eWLAN_PAL_STATUS_E_FAILURE if recovery is not possible
                  or recovery fails
===========================================================================*/
wpt_status dxeErrHandler
(
    WLANDXE_ChannelCBType    *channelCb,
    wpt_uint32                chStatusReg
)
{
   wpt_uint32 chLDescReg, channelLoop;
   WLANDXE_DescCtrlBlkType *targetCtrlBlk;

   switch ((chStatusReg & WLANDXE_CH_STAT_ERR_CODE_MASK) >>
            WLANDXE_CH_STAT_ERR_CODE_OFFSET)
   {

      case WLANDXE_ERROR_PRG_INV_B2H_SRC_QID:
      case WLANDXE_ERROR_PRG_INV_B2H_DST_QID:
      case WLANDXE_ERROR_PRG_INV_B2H_SRC_IDX:
      case WLANDXE_ERROR_PRG_INV_H2B_SRC_QID:
      case WLANDXE_ERROR_PRG_INV_H2B_DST_QID:
      case WLANDXE_ERROR_PRG_INV_H2B_DST_IDX:
      {
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
         wpalSleep(10);

         if(channelCb->channelType > WDTS_CHANNEL_RX_HIGH_PRI)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%s: Invalid Channel", __func__);
            break;
         }

         wpalReadRegister(channelCb->channelRegister.chDXELstDesclRegAddr, &chLDescReg);

         targetCtrlBlk = channelCb->headCtrlBlk;

         for(channelLoop = 0; channelLoop < channelCb->numDesc; channelLoop++)
         {
            if (targetCtrlBlk->linkedDescPhyAddr == chLDescReg)
            {
                HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                         "%11s :CHx_DESCL: desc ctrl 0x%x, src 0x%x, dst 0x%x, next 0x%x",
                         channelType[channelCb->channelType],
                         targetCtrlBlk->linkedDesc->descCtrl.ctrl,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.srcMemAddrL,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.dstMemAddrL,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.phyNextL);

                targetCtrlBlk = (WLANDXE_DescCtrlBlkType *)targetCtrlBlk->nextCtrlBlk;

                HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                         "%11s :Next Desc: desc ctrl 0x%x, src 0x%x, dst 0x%x, next 0x%x",
                         channelType[channelCb->channelType],
                         targetCtrlBlk->linkedDesc->descCtrl.ctrl,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.srcMemAddrL,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.dstMemAddrL,
                         targetCtrlBlk->linkedDesc->dxedesc.dxe_short_desc.phyNextL);
                break;
            }
            targetCtrlBlk = (WLANDXE_DescCtrlBlkType *)targetCtrlBlk->nextCtrlBlk;
         }
         wpalFwDumpReq(17, 0, 0, 0, 0, 1);
         break;
      }
      case WLANDXE_ERROR_ABORT:
      {
          wpt_uint32 regValue, regValueLocal;
          wpt_uint32 count = 0;
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                   "%s: DXE Abort Error from S/W", __func__);

          wpalReadRegister(WALNDEX_DMA_CSR_ADDRESS, &regValue);
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                   "%s: DXE CSR Value: %08x", __func__,regValue);

          //Execute the BMU recovery only if firmware triggered the ABORT
          if (regValue & WLANDXE_DMA_CSR_FW_BMU_RECOVERY)
          {
              HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                       "%s: Firmware BMU recovery On %08x", __func__,regValue);

              // Clean up the descriptors
              if (eWLAN_PAL_STATUS_SUCCESS !=
                        dxeTXCleanup(tempDxeCtrlBlk))
              {
              HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                       "%s: Host DXE Cleanup Failed!!!!", __func__);
              }

              // Unblock the firmware
              regValue |= WLANDXE_DMA_CSR_HOST_RECOVERY_DONE;
              HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                       "%s: Host DXE Cleanup done %08x", __func__,regValue);
              wpalWriteRegister(WALNDEX_DMA_CSR_ADDRESS, regValue);

              // Wait for firmware to complete the cleanup
              do
              {
                  wpalReadRegister(WALNDEX_DMA_CSR_ADDRESS, &regValue);
                  wpalBusyWait(5000);
                  count++;
                  //count is 60 because wait is for 5 ms and 60*5=300ms
                  //which is the time WD bark happens in firmware
              } while(count < 60 && !(regValue & WLANDXE_DMA_CSR_RECOVERY_DONE));
              HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                       "%s: FW Cleanup done %08x", __func__,regValue);

              //clear all spare bits in CSR
              wpalWriteRegister(WALNDEX_DMA_CSR_ADDRESS,regValue &
                                ~(WLANDXE_DMA_CSR_RECOVERY_DONE |
                                  WLANDXE_DMA_CSR_FW_BMU_RECOVERY |
                                  WLANDXE_DMA_CSR_HOST_RECOVERY_DONE));

              //check if the h/w resources have recovered
              wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU, &regValue);
              wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU_LOCAL, &regValueLocal);
              HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                       "===== count %d ABD %d, ABD LOCAL %d =====", count,
                       regValue, regValueLocal);
              if(regValue == 0 || regValueLocal == 0)
              {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                           "%s:  HW resources have not recovered", __func__);
                  return eWLAN_PAL_STATUS_E_FAILURE;
              }

              return eWLAN_PAL_STATUS_SUCCESS;
          }
          break;
      }
      default:
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%s: No Debug Inormation", __func__);
         break;
      }

   }
   return eWLAN_PAL_STATUS_E_FAILURE;
}
/*==========================================================================
  @  Function Name
      dxeTxThreadChannelDebugHandler

  @  Description
      Dump TX channel information

  @  Parameters
      Wwpt_msg               *msgPtr

  @  Return
      NONE

===========================================================================*/
void dxeTxThreadChannelDebugHandler
(
    wpt_msg               *msgPtr
)
{
   wpt_uint8                channelLoop;
   wpt_log_data_stall_channel_type channelLog;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Whatever RIVA power condition try to wakeup RIVA through SMSM
    * This will not simply wakeup RIVA
    * Just incase TX not wanted stuck, Trigger TX again */
   for(channelLoop = 0; channelLoop < WDTS_CHANNEL_RX_LOW_PRI; channelLoop++)
   {
      dxeChannelMonitor("******** Get Descriptor Snapshot ",
                        &tempDxeCtrlBlk->dxeChannel[channelLoop],
                        &channelLog);
      dxeChannelRegisterDump(&tempDxeCtrlBlk->dxeChannel[channelLoop],
                             "Abnormal successive empty interrupt",
                             &channelLog);
      dxeChannelAllDescDump(&tempDxeCtrlBlk->dxeChannel[channelLoop],
                            channelLoop,
                            &channelLog);

      wpalMemoryCopy(channelLog.channelName,
                     channelType[channelLoop],
                     WPT_TRPT_CHANNEL_NAME);
      wpalPacketStallUpdateInfo(NULL, NULL, &channelLog, channelLoop);
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "================== DXE Dump End ======================");
   wpalMemoryFree(msgPtr);

#ifdef FEATURE_WLAN_DIAG_SUPPORT
   wpalPacketStallDumpLog();
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}

/*==========================================================================
  @  Function Name
      dxeRxThreadChannelDebugHandler

  @  Description
      Dump RX channel information

  @  Parameters
      Wwpt_msg               *msgPtr

  @  Return
      NONE

===========================================================================*/
void dxeRxThreadChannelDebugHandler
(
    wpt_msg               *msgPtr
)
{
   wpt_status               status = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint8                channelLoop;
   wpt_log_data_stall_channel_type channelLog;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Whatever RIVA power condition try to wakeup RIVA through SMSM
    * This will not simply wakeup RIVA
    * Just incase TX not wanted stuck, Trigger TX again */
   for(channelLoop = WDTS_CHANNEL_RX_LOW_PRI; channelLoop < WDTS_CHANNEL_MAX; channelLoop++)
   {
      if (!WLANDXE_IS_VALID_CHANNEL(channelLoop))
         continue;

      dxeChannelMonitor("******** Get Descriptor Snapshot ",
                        &tempDxeCtrlBlk->dxeChannel[channelLoop],
                        &channelLog);
      dxeChannelRegisterDump(&tempDxeCtrlBlk->dxeChannel[channelLoop],
                             "Abnormal successive empty interrupt",
                             &channelLog);
      dxeChannelAllDescDump(&tempDxeCtrlBlk->dxeChannel[channelLoop],
                            channelLoop, &channelLog);

      wpalMemoryCopy(channelLog.channelName,
                     channelType[channelLoop],
                     WPT_TRPT_CHANNEL_NAME);
      wpalPacketStallUpdateInfo(NULL, NULL, &channelLog, channelLoop);

   }

   /* Now serialise the message through Tx thread also to make sure
    * no register access when RIVA is in powersave */
   /*Use the same message pointer just change the call back function */
   msgPtr->callback = dxeTxThreadChannelDebugHandler;
   status = wpalPostTxMsg(WDI_GET_PAL_CTX(),
                          msgPtr);
   if ( eWLAN_PAL_STATUS_SUCCESS != status )
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "Tx thread state dump req serialize fail status=%d",
               status);
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}

/*==========================================================================
  @  Function Name 
      dxeCtrlBlkAlloc

  @  Description 
      Allocate DXE Control block
      DXE control block will used by Host DXE driver only, internal structure
      Will make ring linked list

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeCtrlBlkAlloc
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   unsigned int              idx, fIdx;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   WLANDXE_DescCtrlBlkType  *freeCtrlBlk = NULL;
   WLANDXE_DescCtrlBlkType  *prevCtrlBlk = NULL;
   WLANDXE_DescCtrlBlkType  *nextCtrlBlk = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity check */
   if((NULL == dxeCtrlBlk) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeCtrlBlkAlloc Channel Entry is not valid");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   /* Allocate pre asigned number of control blocks */
   for(idx = 0; idx < channelEntry->numDesc; idx++)
   {
      currentCtrlBlk = (WLANDXE_DescCtrlBlkType *)wpalMemoryAllocate(sizeof(WLANDXE_DescCtrlBlkType));
      if(NULL == currentCtrlBlk)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeCtrlBlkOpen MemAlloc Fail for channel %d",
                  channelEntry->channelType);
         freeCtrlBlk = channelEntry->headCtrlBlk;
         for(fIdx = 0; fIdx < idx; fIdx++)
         {
            if(NULL == freeCtrlBlk)
            {
               break;
            }

            nextCtrlBlk = freeCtrlBlk->nextCtrlBlk;
            wpalMemoryFree((void *)freeCtrlBlk);
            freeCtrlBlk = nextCtrlBlk;
         }
         return eWLAN_PAL_STATUS_E_FAULT;
      }

      memset((wpt_uint8 *)currentCtrlBlk, 0, sizeof(WLANDXE_DescCtrlBlkType));
      /* Initialize common elements first */
      currentCtrlBlk->xfrFrame          = NULL;
      currentCtrlBlk->linkedDesc        = NULL;
      currentCtrlBlk->linkedDescPhyAddr = 0;
      currentCtrlBlk->ctrlBlkOrder      = idx;

      /* This is the first control block allocated
       * Next Control block is not allocated yet
       * head and tail must be first control block */
      if(0 == idx)
      {
         currentCtrlBlk->nextCtrlBlk = NULL;
         channelEntry->headCtrlBlk   = currentCtrlBlk;
         channelEntry->tailCtrlBlk   = currentCtrlBlk;
      }
      /* This is not first, not last control block
       * previous control block may has next linked block */
      else if((0 < idx) && (idx < (channelEntry->numDesc - 1)))
      {
         prevCtrlBlk->nextCtrlBlk = currentCtrlBlk;
      }
      /* This is last control blocl
       * next control block for the last control block is head, first control block
       * then whole linked list made RING */
      else if((channelEntry->numDesc - 1) == idx)
      {
         prevCtrlBlk->nextCtrlBlk    = currentCtrlBlk;
         currentCtrlBlk->nextCtrlBlk = channelEntry->headCtrlBlk;
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeCtrlBlkOpen Invalid Ctrl Blk location %d",
                  channelEntry->channelType);
         wpalMemoryFree(currentCtrlBlk);
         return eWLAN_PAL_STATUS_E_FAULT;
      }

      prevCtrlBlk = currentCtrlBlk;
      channelEntry->numFreeDesc++;
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,"%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      dxeDescLinkAlloc

  @  Description 
      Allocate DXE descriptor
      DXE descriptor will be shared by DXE host driver and RIVA DXE engine
      Will make RING linked list
      Will be linked with Descriptor control block one by one

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeDescAllocAndLink
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status      = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescType         *currentDesc = NULL;
   WLANDXE_DescType         *prevDesc    = NULL;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   unsigned int              idx;
   void                     *physAddressAlloc = NULL;
   wpt_uint32                physAddress;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity Check */
   if((NULL == dxeCtrlBlk) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeDescLinkAlloc Channel Entry is not valid");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   currentCtrlBlk = channelEntry->headCtrlBlk;

   /* allocate all DXE descriptors for this channel in one chunk */
   channelEntry->descriptorAllocation = (WLANDXE_DescType *)
      wpalDmaMemoryAllocate(sizeof(WLANDXE_DescType)*channelEntry->numDesc,
                            &physAddressAlloc);
   physAddress = (wpt_uint32) (uintptr_t)(physAddressAlloc);
   if(NULL == channelEntry->descriptorAllocation)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeDescLinkAlloc Descriptor Alloc Fail");
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }
   currentDesc = channelEntry->descriptorAllocation;

   /* Allocate pre asigned number of descriptor */
   for(idx = 0; idx < channelEntry->numDesc; idx++)
   {
      // descriptors were allocated in a chunk -- use the current one
      if(NULL == currentDesc)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeDescLinkAlloc MemAlloc Fail for channel %d",
                  channelEntry->channelType);
         return eWLAN_PAL_STATUS_E_FAULT;
      }
      memset((wpt_uint8 *)currentDesc, 0, sizeof(WLANDXE_DescType));
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
               "Allocated Descriptor VA %pK, PA %pK", currentDesc, physAddressAlloc);

      currentCtrlBlk->linkedDesc        = currentDesc;
      currentCtrlBlk->linkedDescPhyAddr = physAddress;
      /* First descriptor, next none
       * descriptor bottom location is first descriptor address */
      if(0 == idx)
      {
         currentDesc->dxedesc.dxe_short_desc.phyNextL = 0;
         channelEntry->DescBottomLoc                  = currentDesc;
         channelEntry->descBottomLocPhyAddr           = physAddress;
      }
      /* Not first, not last descriptor
       * may make link for previous descriptor with current descriptor
       * ENDIAN SWAP needed ????? */
      else if((0 < idx) && (idx < (channelEntry->numDesc - 1)))
      {
         prevDesc->dxedesc.dxe_short_desc.phyNextL = 
                                WLANDXE_U32_SWAP_ENDIAN(physAddress);
      }
      /* Last descriptor
       * make a ring by asign next pointer as first descriptor
       * ENDIAN SWAP NEEDED ??? */
      else if((channelEntry->numDesc - 1) == idx)
      {
         prevDesc->dxedesc.dxe_short_desc.phyNextL    = 
                                WLANDXE_U32_SWAP_ENDIAN(physAddress);
         currentDesc->dxedesc.dxe_short_desc.phyNextL =
                                WLANDXE_U32_SWAP_ENDIAN(channelEntry->headCtrlBlk->linkedDescPhyAddr);
      }

      /* If Current Channel is RX channel PAL Packet and OS packet buffer should be
       * Pre allocated and physical address must be assigned into
       * Corresponding DXE Descriptor */
      if((WDTS_CHANNEL_RX_LOW_PRI  == channelEntry->channelType) ||
         (WDTS_CHANNEL_RX_HIGH_PRI == channelEntry->channelType) ||
         (WDTS_CHANNEL_RX_LOG == channelEntry->channelType))
      {
         status = dxeRXFrameSingleBufferAlloc(dxeCtrlBlk,
                                              channelEntry,
                                              currentCtrlBlk);
         if( !WLAN_PAL_IS_STATUS_SUCCESS(status) )
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeDescLinkAlloc RX Buffer Alloc Fail for channel %d",
                     channelEntry->channelType);
            return status;
         }
         --channelEntry->numFreeDesc;
      }

      if((WDTS_CHANNEL_TX_LOW_PRI == channelEntry->channelType) ||
         (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
      {
         currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_write;
         currentDesc->dxedesc.dxe_short_desc.dstMemAddrL = channelEntry->extraConfig.refWQ_swapped;
      }
      else if((WDTS_CHANNEL_RX_LOW_PRI == channelEntry->channelType) ||
              (WDTS_CHANNEL_RX_HIGH_PRI == channelEntry->channelType)||
              (WDTS_CHANNEL_RX_LOG == channelEntry->channelType))
      {
         currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_read;
         currentDesc->dxedesc.dxe_short_desc.srcMemAddrL = channelEntry->extraConfig.refWQ_swapped;
      }
      else
      {
         /* Just in case. H2H RX channel, do nothing
          * By Definition this must not happen */
      }

      currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
      prevDesc       = currentDesc;

      // advance to the next pre-allocated descriptor in the chunk
      currentDesc++;
      physAddress = (physAddress + sizeof(WLANDXE_DescType));
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name

  @  Description 

  @  Parameters

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeSetInterruptPath
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk
)
{
   wpt_status                 status        = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                 interruptPath = 0;
   wpt_uint32                 idx;
   WLANDXE_ChannelCBType     *channelEntry = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   foreach_valid_channel(idx)
   {
      channelEntry = &dxeCtrlBlk->dxeChannel[idx];
      if((WDTS_CHANNEL_TX_LOW_PRI == channelEntry->channelType) ||
         (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
      {
         interruptPath |= (1 << channelEntry->assignedDMAChannel);
      }
      else if((WDTS_CHANNEL_RX_LOW_PRI == channelEntry->channelType) ||
              (WDTS_CHANNEL_RX_HIGH_PRI == channelEntry->channelType)||
              (WDTS_CHANNEL_RX_FW_LOG == channelEntry->channelType)  ||
              (WDTS_CHANNEL_RX_LOG == channelEntry->channelType))
      {
         interruptPath |= (1 << (channelEntry->assignedDMAChannel + 16));
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "H2H TEST RX???? %d", channelEntry->channelType);
      }
   }
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
            "Interrupt Path Must be 0x%x", interruptPath);
   dxeCtrlBlk->interruptPath = interruptPath;
   wpalWriteRegister(WLANDXE_CCU_DXE_INT_SELECT, interruptPath);

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name
      dxeEngineCoreStart 

  @  Description 
      Trigger to start RIVA DXE Hardware

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block

  @  Return
      void

===========================================================================*/
static void dxeEngineCoreStart
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk
)
{
   wpt_uint32                 registerData = 0;
   wpt_uint8                  readRetry;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

#ifdef WCN_PRONTO
   /* Read default */
   wpalReadRegister(WLANDXE_CCU_SOFT_RESET, &registerData);
   registerData |= WLANDXE_DMA_CCU_DXE_RESET_MASK;

   /* Make reset */
   wpalWriteRegister(WLANDXE_CCU_SOFT_RESET, registerData);

   /* Clear reset */
   registerData &= ~WLANDXE_DMA_CCU_DXE_RESET_MASK;
   wpalWriteRegister(WLANDXE_CCU_SOFT_RESET, registerData);
#else
   /* START This core init is not needed for the integrated system */
   /* Reset First */
   registerData = WLANDXE_DMA_CSR_RESET_MASK;
   wpalWriteRegister(WALNDEX_DMA_CSR_ADDRESS,
                          registerData);
#endif /* WCN_PRONTO */

   for(readRetry = 0; readRetry < WLANDXE_CSR_MAX_READ_COUNT; readRetry++)
   {
      wpalWriteRegister(WALNDEX_DMA_CSR_ADDRESS,
                        WLANDXE_CSR_DEFAULT_ENABLE);
      wpalReadRegister(WALNDEX_DMA_CSR_ADDRESS, &registerData);
      if(!(registerData & WLANDXE_DMA_CSR_EN_MASK))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s CSR 0x%x, count %d",
                  __func__, registerData, readRetry);
         /* CSR is not valid value, re-try to write */
         wpalBusyWait(WLANDXE_CSR_NEXT_READ_WAIT);
      }
      else
      {
         break;
      }
   }
   if(WLANDXE_CSR_MAX_READ_COUNT == readRetry)
   {
      /* MAX wait, still cannot write correct value
       * Panic device */
      wpalDevicePanic();
   }

   /* Is This needed?
    * Not sure, revisit with integrated system */
   /* END This core init is not needed for the integrated system */

   dxeSetInterruptPath(dxeCtrlBlk);
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
}

/*==========================================================================
  @  Function Name 
      dxeChannelInitProgram

  @  Description 
      Program RIVA DXE engine register with initial value
      What must be programmed
         - Source Address             (SADRL, chDXESadrlRegAddr)
         - Destination address        (DADRL, chDXEDadrlRegAddr)
         - Next Descriptor address    (DESCL, chDXEDesclRegAddr)
         - current descriptor address (LST_DESCL, chDXELstDesclRegAddr)

      Not need to program now
         - Channel Control register   (CH_CTRL, chDXECtrlRegAddr)
           TX : Have to program to trigger send out frame
           RX : programmed by DXE engine

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelInitProgram
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                idx;
   WLANDXE_DescType         *currentDesc = NULL;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity Check */
   if((NULL == dxeCtrlBlk) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelInitProgram Channel Entry is not valid");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   /* Program Source address and destination adderss */
   if(!channelEntry->channelConfig.useShortDescFmt)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelInitProgram Long Descriptor not support yet");
      return eWLAN_PAL_STATUS_E_FAILURE;
   }

   /* Common register area */
   /* Next linked list Descriptor pointer */
   status = wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                   channelEntry->headCtrlBlk->linkedDescPhyAddr);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelInitProgram Write DESC Address register fail");
      return status;
   }

   if((WDTS_CHANNEL_TX_LOW_PRI  == channelEntry->channelType) ||
      (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
   {
      /* Program default registers */
      /* TX DMA channel, DMA destination address is work Q */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXEDadrlRegAddr,
                                      channelEntry->channelConfig.refWQ);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelInitProgram Write TX DAddress register fail");
         return status;
      }
   }
   else if((WDTS_CHANNEL_RX_LOW_PRI  == channelEntry->channelType) ||
           (WDTS_CHANNEL_RX_HIGH_PRI == channelEntry->channelType) ||
           (WDTS_CHANNEL_RX_LOG == channelEntry->channelType))
   {
      /* Initialize Descriptor control Word First */
      currentCtrlBlk = channelEntry->headCtrlBlk;
      for(idx = 0; idx < channelEntry->channelConfig.nDescs; idx++)
      {
         currentDesc = currentCtrlBlk->linkedDesc;
         currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;         
      }

      /* RX DMA channel, DMA source address is work Q */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXESadrlRegAddr,
                                      channelEntry->channelConfig.refWQ);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelInitProgram Write RX SAddress WQ register fail");
         return status;
      }

      /* RX DMA channel, Program pre allocated destination Address */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXEDadrlRegAddr,
                                      WLANDXE_U32_SWAP_ENDIAN(channelEntry->DescBottomLoc->dxedesc.dxe_short_desc.phyNextL));
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelInitProgram Write RX DAddress register fail");
         return status;
      }

      /* RX Channels, default Control registers MUST BE ENABLED */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                             channelEntry->extraConfig.chan_mask);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelInitProgram Write RX Control register fail");
         return status;
      }
   }
   else
   {
      /* H2H test channel, not use work Q */
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}


/*==========================================================================
  @  Function Name 
      dxeChannelStart

  @  Description 
      Start Specific Channel

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelStart
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                regValue   = 0;
   wpt_uint32                intMaskVal = 0;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   channelEntry->extraConfig.chEnabled    = eWLAN_PAL_TRUE;
   channelEntry->extraConfig.chConfigured = eWLAN_PAL_TRUE;

   /* Enable individual channel
    * not to break current channel setup, first read register */
   status = wpalReadRegister(WALNDEX_DMA_CH_EN_ADDRESS,
                                  &regValue);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStart Read Channel Enable register fail");
      return status;
   }

   /* Enable Channel specific Interrupt */
   status = wpalReadRegister(WLANDXE_INT_MASK_REG_ADDRESS,
                                  &intMaskVal);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStart Read INT_MASK register fail");
      return status;         
   }
   intMaskVal |= channelEntry->extraConfig.intMask;
   status = wpalWriteRegister(WLANDXE_INT_MASK_REG_ADDRESS,
                                   intMaskVal);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStart Write INT_MASK register fail");
      return status;         
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name
      dxeChannelStop

  @  Description 
      Stop Specific Channel

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelStop
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                intMaskVal = 0;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if((NULL == dxeCtrlBlk) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStop Invalid arg input");
      return eWLAN_PAL_STATUS_E_INVAL; 
   }

   if ( (channelEntry->extraConfig.chEnabled != eWLAN_PAL_TRUE) ||
        (channelEntry->extraConfig.chConfigured != eWLAN_PAL_TRUE))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStop channels are not enabled ");
      return status; 
   }
   /* Maskout interrupt */
   status = wpalReadRegister(WLANDXE_INT_MASK_REG_ADDRESS,
                                  &intMaskVal);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStop Read INT_MASK register fail");
      return status;         
   }
   intMaskVal ^= channelEntry->extraConfig.intMask;
   status = wpalWriteRegister(WLANDXE_INT_MASK_REG_ADDRESS,
                                   intMaskVal);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStop Write INT_MASK register fail");
      return status;         
   }

   channelEntry->extraConfig.chEnabled    = eWLAN_PAL_FALSE;

   /* Stop Channel ??? */
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      dxeChannelClose

  @  Description 
      Close Specific Channel
      Free pre allocated RX frame buffer if RX channel
      Free DXE descriptor for each channel
      Free Descriptor control block for each channel

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelClose
(
   WLANDXE_CtrlBlkType     *dxeCtrlBlk,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status            = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                idx;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk    = NULL;
   WLANDXE_DescCtrlBlkType  *nextCtrlBlk       = NULL;
   WLANDXE_DescType         *currentDescriptor = NULL;
   WLANDXE_DescType         *nextDescriptor    = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if((NULL == dxeCtrlBlk) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelStop Invalid arg input");
      return eWLAN_PAL_STATUS_E_INVAL; 
   }

   currentCtrlBlk    = channelEntry->headCtrlBlk;
   if(NULL != currentCtrlBlk)
   {
      currentDescriptor = currentCtrlBlk->linkedDesc;
      for(idx = 0; idx < channelEntry->numDesc; idx++)
      {
          if (idx + 1 != channelEntry->numDesc)
          {
              nextCtrlBlk    = currentCtrlBlk->nextCtrlBlk;
              nextDescriptor = nextCtrlBlk->linkedDesc;
          }
          else
          {
              nextCtrlBlk = NULL;
              nextDescriptor = NULL;
          }
          if((WDTS_CHANNEL_RX_LOW_PRI  == channelEntry->channelType) ||
             (WDTS_CHANNEL_RX_HIGH_PRI == channelEntry->channelType) ||
             (WDTS_CHANNEL_RX_LOG == channelEntry->channelType))
          {
            if (NULL != currentCtrlBlk->xfrFrame)
            {
               wpalUnlockPacket(currentCtrlBlk->xfrFrame);
               wpalPacketFree(currentCtrlBlk->xfrFrame);
            }
         }
         /*  
          *  It is the responsibility of DXE to walk through the 
          *  descriptor chain and unlock any pending packets (if 
          *  locked). 
          */
         if((WDTS_CHANNEL_TX_LOW_PRI  == channelEntry->channelType) ||
            (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
         {
             if((NULL != currentCtrlBlk->xfrFrame) && 
                     (eWLAN_PAL_STATUS_SUCCESS == wpalIsPacketLocked(currentCtrlBlk->xfrFrame)))
               {
                  wpalUnlockPacket(currentCtrlBlk->xfrFrame);
                  wpalPacketFree(currentCtrlBlk->xfrFrame);
               }
         }
         wpalMemoryFree(currentCtrlBlk);

         currentCtrlBlk    = nextCtrlBlk;
         currentDescriptor = nextDescriptor;
         if(NULL == currentCtrlBlk)
         {
            /* Already reach last of the control block
             * Not need to process anymore, break */
            break;
         }
      }
   }

   // descriptors were allocated as a single chunk so free the chunk
   if(NULL != channelEntry->descriptorAllocation)
   {
      wpalDmaMemoryFree(channelEntry->descriptorAllocation);
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name
      dxeChannelCleanInt

  @  Description 
      Clean up interrupt from RIVA HW
      After Host finish to handle interrupt, interrupt signal must be cleaned up
      Otherwise next interrupt will not be generated

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
      wpt_uint32              *chStat
                               Channel Status register value

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeChannelCleanInt
(
   WLANDXE_ChannelCBType   *channelEntry,
   wpt_uint32              *chStat
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Read Channel Status Register to know why INT Happen */
   status = wpalReadRegister(channelEntry->channelRegister.chDXEStatusRegAddr,
                                  chStat);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelCleanInt Read CH STAT register fail");
      return eWLAN_PAL_STATUS_E_FAULT;         
   }
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Channel INT Clean, Status 0x%x",
            channelType[channelEntry->channelType], *chStat);

   /* Clean up all the INT within this channel */
   status = wpalWriteRegister(WLANDXE_INT_CLR_ADDRESS,
                                   (1 << channelEntry->assignedDMAChannel));
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelCleanInt Write CH Clean register fail");
      return eWLAN_PAL_STATUS_E_FAULT;         
   }

   /* Clean up Error INT Bit */
   if(WLANDXE_CH_STAT_INT_ERR_MASK & *chStat)
   {
      status = wpalWriteRegister(WLANDXE_INT_ERR_CLR_ADDRESS,
                                      (1 << channelEntry->assignedDMAChannel));
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelCleanInt Read CH STAT register fail");
         return eWLAN_PAL_STATUS_E_FAULT;         
      }
   }

   /* Clean up DONE INT Bit */
   if(WLANDXE_CH_STAT_INT_DONE_MASK & *chStat)
   {
      status = wpalWriteRegister(WLANDXE_INT_DONE_CLR_ADDRESS,
                                      (1 << channelEntry->assignedDMAChannel));
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelCleanInt Read CH STAT register fail");
         return eWLAN_PAL_STATUS_E_FAULT;         
      }
   }

   /* Clean up ED INT Bit */
   if(WLANDXE_CH_STAT_INT_ED_MASK & *chStat)
   {
      status = wpalWriteRegister(WLANDXE_INT_ED_CLR_ADDRESS,
                                      (1 << channelEntry->assignedDMAChannel));
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelCleanInt Read CH STAT register fail");
         return eWLAN_PAL_STATUS_E_FAULT;         
      }
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
/*==========================================================================
  @  Function Name
			      dxeRXResourceAvailableTimerExpHandler

  @  Description
      During pre-set timeperiod, if free available RX buffer is not allocated
      Trigger Driver re-loading to recover RX dead end

  @  Parameters
   v_VOID_t     *usrData
                DXE context

  @  Return
      NONE

===========================================================================*/
void dxeRXResourceAvailableTimerExpHandler
(
   void    *usrData
)
{
   WLANDXE_CtrlBlkType      *dxeCtxt    = NULL;
   wpt_uint32               numRxFreePackets;
   wpt_uint32               numAllocFailures;

   dxeCtxt = (WLANDXE_CtrlBlkType *)usrData;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "RX Low resource, Durign wait time period %d, RX resource not allocated",
            wpalGetDxeReplenishRXTimerVal());

   //This API wil also try to replenish packets
   wpalGetNumRxFreePacket(&numRxFreePackets);
   wpalGetNumRxPacketAllocFailures(&numAllocFailures);

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "Free Packets: %u, Alloc Failures: %u",
            numRxFreePackets, numAllocFailures);
   if (numRxFreePackets > 0)
   {
      /* If no. of free packets is greater than 0, it means
       * that some packets were replenished and can be used
       * by DXE to receive frames. So try to restart the
       * resourceAvailable timer here, it will be stopped
       * by the DXE's low resource callback if atleast one
       * free packet reaches DXE.
       */
      if (NULL != dxeCtxt)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%s: Replenish successful. Restart the Rx Low resource timer",
                  __func__);
         wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer,
                        wpalGetDxeReplenishRXTimerVal());
         return;
      }
   }
   if(wpalIsDxeSSREnable())
   {
      if (NULL != dxeCtxt)
         dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;

      wpalWlanReload(VOS_DXE_FAILURE);

      if (NULL != usrData)
         dxeStartSSRTimer((WLANDXE_CtrlBlkType *)usrData);
   }
   else
   {
       wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer,
                      wpalGetDxeReplenishRXTimerVal());
   }
   return;
}
#endif

/*==========================================================================
  @  Function Name
     dxeStartSSRTimer

  @  Description
      Start the dxeSSRTimer after issuing the FIQ to restart the WCN chip,
      this makes sure that if the chip does not respond to the FIQ within
      the timeout period the dxeSSRTimer expiration handler will take the
      appropriate action.

  @  Parameters
      NONE

  @  Return
      NONE

===========================================================================*/
static void dxeStartSSRTimer
(
  WLANDXE_CtrlBlkType     *dxeCtxt
)
{
   if(VOS_TIMER_STATE_RUNNING !=
      wpalTimerGetCurStatus(&dxeCtxt->dxeSSRTimer))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "%s: Starting SSR Timer",__func__);
      wpalTimerStart(&dxeCtxt->dxeSSRTimer,
                     T_WLANDXE_SSR_TIMEOUT);
   }
}

/*==========================================================================
  @  Function Name
     dxeSSRTimerExpHandler

  @  Description
      Issue an explicit subsystem restart of the wcnss subsystem if the
      WCN chip does not respond to the FIQ within the timeout period

  @  Parameters
   v_VOID_t     *usrData

  @  Return
      NONE

===========================================================================*/
void dxeSSRTimerExpHandler
(
   void    *usrData
)
{
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "DXE not shutdown %d ms after FIQ!! Issue SSR",
            T_WLANDXE_SSR_TIMEOUT);
   wpalRivaSubystemRestart();

   return;
}

/*==========================================================================
  @  Function Name 
      dxeRXPacketAvailableCB

  @  Description 
      If RX frame handler encounts RX buffer pool empty condition,
      DXE RX handle loop will be blocked till get available RX buffer pool.
      When new RX buffer pool available, Packet available CB function will
      be called.

  @  Parameters
   wpt_packet   *freePacket
                Newly allocated RX buffer
   v_VOID_t     *usrData
                DXE context

  @  Return
      NONE

===========================================================================*/
void dxeRXPacketAvailableCB
(
   wpt_packet   *freePacket,
   v_VOID_t     *usrData
)
{
   WLANDXE_CtrlBlkType       *dxeCtxt = NULL;
   wpt_status                status;

   /* Simple Sanity */
   if((NULL == freePacket) || (NULL == usrData))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "Get Free RX Buffer fail, Critical Error");
      HDXE_ASSERT(0);
      return;
   }

   dxeCtxt = (WLANDXE_CtrlBlkType *)usrData;

   if(WLANDXE_CTXT_COOKIE != dxeCtxt->dxeCookie)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "DXE Context data corrupted, Critical Error");
      HDXE_ASSERT(0);
      return;
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
            "DXE RX packet available, post MSG to RX Thread");

   dxeCtxt->freeRXPacket = freePacket;

   /* Serialize RX Packet Available message upon RX thread */
   if (NULL == dxeCtxt->rxPktAvailMsg)
   {
       HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "DXE NULL pkt");
       HDXE_ASSERT(0);
       return;
   }

   status = wpalPostRxMsg(WDI_GET_PAL_CTX(),
                          dxeCtxt->rxPktAvailMsg);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "dxeRXPacketAvailableCB serialize fail");
   }

   return;
}

/*==========================================================================
  @  Function Name 
      dxeRXFrameSingleBufferAlloc

  @  Description 
      Allocate Platform packet buffer to prepare RX frame
      RX frame memory space must be pre allocted and must be asigned to
      descriptor
      then whenever DMA engine want to tranfer frame from BMU,
      buffer must be ready

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
      WLANDXE_DescCtrlBlkType  currentCtrlBlock
                               current control block which have to be asigned 
                               frame buffer

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeRXFrameSingleBufferAlloc
(
   WLANDXE_CtrlBlkType      *dxeCtxt,
   WLANDXE_ChannelCBType    *channelEntry,
   WLANDXE_DescCtrlBlkType  *currentCtrlBlock
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   wpt_packet               *currentPalPacketBuffer = NULL;
   WLANDXE_DescType         *currentDesc            = NULL;
   wpt_iterator              iterator;
   wpt_uint32                allocatedSize          = 0;
   void                     *physAddress            = NULL;

   currentDesc            = currentCtrlBlock->linkedDesc;

   if(currentDesc->descCtrl.valid)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "This Descriptor is valid, Do not refill");
      return eWLAN_PAL_STATUS_E_EXISTS;
   }

   /* First check if a packet pointer has already been provided by a previously
      invoked Rx packet available callback. If so use that packet. */
   if (dxeCtxt->rxPalPacketUnavailable)
   {
      if (NULL != dxeCtxt->freeRXPacket)
      {
         currentPalPacketBuffer = dxeCtxt->freeRXPacket;
         dxeCtxt->rxPalPacketUnavailable = eWLAN_PAL_FALSE;
         dxeCtxt->freeRXPacket = NULL;

         if (channelEntry->doneIntDisabled)
         {
            wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                              channelEntry->extraConfig.chan_mask);
            channelEntry->doneIntDisabled = 0;
         }
      }
      else if (VOS_TIMER_STATE_RUNNING !=
               wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer))
      {
         if (eWLAN_PAL_STATUS_SUCCESS !=
             wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer,
                            wpalGetDxeReplenishRXTimerVal()))
         {
             HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                      "RX resource available timer not started");
         }
         else
            dxeEnvBlk.rx_low_resource_timer = 1;
      }
   }
   else if(!dxeCtxt->rxPalPacketUnavailable)
   {
      /* Allocate platform Packet buffer and OS Frame Buffer at here */
      currentPalPacketBuffer = wpalPacketAlloc(eWLAN_PAL_PKT_TYPE_RX_RAW,
                                            WLANDXE_DEFAULT_RX_OS_BUFFER_SIZE,
                                            dxeRXPacketAvailableCB,
                                            (void *)dxeCtxt);

      if(NULL == currentPalPacketBuffer)
      {
         dxeCtxt->rxPalPacketUnavailable = eWLAN_PAL_TRUE;
#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
         /* Out of RX free buffer,
          * Start timer to recover from RX dead end */
         if(VOS_TIMER_STATE_RUNNING !=
            wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer))
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                     "RX Low resource, wait available resource");
            if (eWLAN_PAL_STATUS_SUCCESS !=
                wpalTimerStart(&dxeCtxt->rxResourceAvailableTimer,
                           wpalGetDxeReplenishRXTimerVal()))
            {
                HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                         "RX resource available timer not started");
            }
            else
               dxeEnvBlk.rx_low_resource_timer = 1;
         }
#endif
      }
   }
   
   if(NULL == currentPalPacketBuffer)
   {
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }

   currentCtrlBlock->xfrFrame       = currentPalPacketBuffer;
   currentPalPacketBuffer->pktType  = eWLAN_PAL_PKT_TYPE_RX_RAW;
   currentPalPacketBuffer->pBD      = NULL;
   currentPalPacketBuffer->pBDPhys  = NULL;
   currentPalPacketBuffer->BDLength = 0;

   if (channelEntry->channelType == WDTS_CHANNEL_RX_FW_LOG)
      wpalPacketRawTrimHead(currentCtrlBlock->xfrFrame, WLANDXE_NL_HEADER_SZ);

   status = wpalLockPacketForTransfer(currentPalPacketBuffer);

   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameBufferAlloc unable to lock packet");
      return status;
   }

   /* Init iterator to get physical os buffer address */
   status = wpalIteratorInit(&iterator, currentPalPacketBuffer);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameBufferAlloc iterator init fail");
      return status;
   }
   status = wpalIteratorNext(&iterator,
                             currentPalPacketBuffer,
                             &physAddress,
                             &allocatedSize);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameBufferAlloc iterator Get Next pointer fail");
      return status;
   }
   currentPalPacketBuffer->pBDPhys = physAddress;

   /* DXE descriptor must have SWAPPED addres in it's structure
    * !!! SWAPPED !!! */
   currentDesc->dxedesc.dxe_short_desc.dstMemAddrL =
                                       WLANDXE_U32_SWAP_ENDIAN((wpt_uint32)(uintptr_t)currentPalPacketBuffer->pBDPhys);

   return status;
}

/*==========================================================================
  @  Function Name 
      dxeRXFrameRefillRing

  @  Description 
      Allocate Platform packet buffers to try to fill up the DXE Rx ring

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
      
  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeRXFrameRefillRing
(
   WLANDXE_CtrlBlkType      *dxeCtxt,
   WLANDXE_ChannelCBType    *channelEntry
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = channelEntry->tailCtrlBlk;
   WLANDXE_DescType         *currentDesc    = NULL;

   while(channelEntry->numFreeDesc > 0)
   {
      /* Current Control block is free
       * and associated frame buffer is not linked with control block anymore
       * allocate new frame buffer for current control block */
      status = dxeRXFrameSingleBufferAlloc(dxeCtxt,
                                           channelEntry,
                                           currentCtrlBlk);

      if((eWLAN_PAL_STATUS_SUCCESS != status) &&
         (eWLAN_PAL_STATUS_E_EXISTS != status))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                  "dxeRXFrameRefillRing, out of RX buffer pool, break here");
         break;
      }

      if(eWLAN_PAL_STATUS_E_EXISTS == status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXFrameRefillRing, Descriptor Non-Empry");
      }

      currentDesc = currentCtrlBlk->linkedDesc;
      currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_read;

      /* Issue a dummy read from the DXE descriptor DDR location to ensure
         that any posted writes are reflected in memory before DXE looks at
         the descriptor. */
      if(channelEntry->extraConfig.cw_ctrl_read != currentDesc->descCtrl.ctrl)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXFrameRefillRing, Descriptor write failed");
         ++channelEntry->desc_write_fail_count;
         //HDXE_ASSERT(0);
      }

      /* Kick off the DXE ring, if not in any power save mode */
      if(WLANDXE_POWER_STATE_FULL == dxeCtxt->hostPowerState)
      {
         wpalWriteRegister(WALNDEX_DMA_ENCH_ADDRESS,
                           1 << channelEntry->assignedDMAChannel);
      }
      currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
      if(eWLAN_PAL_STATUS_E_EXISTS != status)
      {
         --channelEntry->numFreeDesc;
      }
   }
   
   channelEntry->tailCtrlBlk = currentCtrlBlk;

   return status;
}

static wpt_uint32 dxeRXLogRefillRing
(
   WLANDXE_CtrlBlkType      *dxeCtxt,
   WLANDXE_ChannelCBType    *channelEntry,
   wpt_uint64                bufferAddr,
   wpt_uint32                bufferLen
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = channelEntry->tailCtrlBlk;
   WLANDXE_DescType         *currentDesc    = NULL;
   wpt_uint32                xfrSize, allocatedLen = 0;

   while(bufferLen > 0 && channelEntry->numFreeDesc > 0)
   {
      /* Current Control block is free
       * and associated frame buffer is not linked with control block anymore
       * allocate new frame buffer for current control block */
      status = dxeRXFrameSingleBufferAlloc(dxeCtxt,
                                           channelEntry,
                                           currentCtrlBlk);

      if((eWLAN_PAL_STATUS_SUCCESS != status) &&
         (eWLAN_PAL_STATUS_E_EXISTS != status))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                  "dxeRXFrameRefillRing, out of RX buffer pool, break here");
         break;
      }

      if(eWLAN_PAL_STATUS_E_EXISTS == status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s, Descriptor Non-Empty",__func__);
      }

      currentDesc = currentCtrlBlk->linkedDesc;
      currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_read;
      xfrSize = WLANDXE_FW_LOGGING_XFSIZE > bufferLen ?
                   bufferLen : WLANDXE_FW_LOGGING_XFSIZE;
      currentDesc->xfrSize = xfrSize;
      allocatedLen += xfrSize;
      bufferLen -= xfrSize;
      wpalPacketSetRxLength(currentCtrlBlk->xfrFrame,
                            xfrSize);

      currentDesc->dxedesc.dxe_short_desc.srcMemAddrL =
              WLANDXE_U32_SWAP_ENDIAN((wpt_uint32)(uintptr_t)bufferAddr);

      /* Issue a dummy read from the DXE descriptor DDR location to ensure
         that any posted writes are reflected in memory before DXE looks at
         the descriptor. */
      if(channelEntry->extraConfig.cw_ctrl_read != currentDesc->descCtrl.ctrl)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s, Descriptor write failed",__func__);
         ++channelEntry->desc_write_fail_count;
      }

      currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
      --channelEntry->numFreeDesc;
      bufferAddr += xfrSize;
   }

   channelEntry->tailCtrlBlk = currentCtrlBlk;

   return allocatedLen;
}
/*==========================================================================
  @  Function Name
      dxeRXFrameRouteUpperLayer

  @  Description 
      Test DXE descriptors and if any RX frame pending within RING,
      Route to upper layer

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
  @  Return
      < 0 Any error happen
      0  No frame pulled from RX RING
      int number of RX frames pulled from RX ring

===========================================================================*/
static wpt_int32 dxeRXFrameRouteUpperLayer
(
   WLANDXE_CtrlBlkType     *dxeCtxt,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   WLANDXE_DescType         *currentDesc    = NULL;
   wpt_uint32                descCtrl, frameCount = 0, i;
   wpt_int32                 ret_val = -1;

   currentCtrlBlk = channelEntry->headCtrlBlk;
   currentDesc    = currentCtrlBlk->linkedDesc;

   /* Descriptoe should be SWAPPED ???? */
   descCtrl = currentDesc->descCtrl.ctrl;

   /* Get frames while VALID bit is not set (DMA complete) and a data 
    * associated with it */
   while(!(WLANDXE_U32_SWAP_ENDIAN(descCtrl) & WLANDXE_DESC_CTRL_VALID) &&
         (eWLAN_PAL_STATUS_SUCCESS == wpalIsPacketLocked(currentCtrlBlk->xfrFrame)) &&
         (currentCtrlBlk->xfrFrame->pInternalData != NULL) &&
         (frameCount < WLANDXE_MAX_REAPED_RX_FRAMES) )
   {
      channelEntry->numTotalFrame++;
      channelEntry->numFreeDesc++;
      status = wpalUnlockPacket(currentCtrlBlk->xfrFrame);

      if (eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXFrameReady unable to unlock packet");
         return ret_val;
      }

      /* This Descriptor is valid, so linked Control block is also valid
       * Linked Control block has pre allocated packet buffer
       * So, just let upper layer knows preallocated frame pointer will be OK */
      /* Reap Rx frames */ 
      rx_reaped_buf[frameCount] = currentCtrlBlk->xfrFrame;
      frameCount++;
      currentCtrlBlk->xfrFrame = NULL;

      /* Now try to refill the ring with empty Rx buffers to keep DXE busy */
      if (WDTS_CHANNEL_RX_FW_LOG != channelEntry->channelType)
          dxeRXFrameRefillRing(dxeCtxt, channelEntry);

      /* Test next contorl block
       * if valid, this control block also has new RX frame must be handled */
      currentCtrlBlk = (WLANDXE_DescCtrlBlkType *)currentCtrlBlk->nextCtrlBlk;
      currentDesc    = currentCtrlBlk->linkedDesc;
      descCtrl       = currentDesc->descCtrl.ctrl;
   }

   /* Update head control block
    * current control block's valid bit was 0
    * next trial first control block must be current control block */
   channelEntry->headCtrlBlk = currentCtrlBlk;

   /* Deliver all the reaped RX frames to upper layers */
   i = 0;
   while(i < frameCount)
   {
      dxeCtxt->rxReadyCB(dxeCtxt->clientCtxt, rx_reaped_buf[i], channelEntry->channelType);
      i++;
   }

   return frameCount;
}

/*==========================================================================
  @  Function Name 
      dxeRXFrameReady

  @  Description 
      Pop frame from descriptor and route frame to upper transport layer
      Assign new platform packet buffer into used descriptor
      Actual frame pop and resource realloc

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeRXFrameReady
(
   WLANDXE_CtrlBlkType     *dxeCtxt,
   WLANDXE_ChannelCBType   *channelEntry,
   wpt_uint32               chStat
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   WLANDXE_DescType         *currentDesc    = NULL;
   wpt_uint32                descCtrl;
   wpt_int32                 frameCount = 0;

   wpt_uint32                descLoop;
   wpt_uint32                invalidatedFound = 0;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity Check */
   if((NULL == dxeCtxt) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameReady Channel Entry is not valid");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   frameCount = dxeRXFrameRouteUpperLayer(dxeCtxt, channelEntry);

   if(0 > frameCount)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameReady RX frame route fail");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if((0 == frameCount) &&
      ((WLANDXE_POWER_STATE_BMPS == dxeCtxt->hostPowerState) ||
       (WLANDXE_POWER_STATE_FULL == dxeCtxt->hostPowerState)))
   {
      /* None of the frame handled and CH is not enabled
       * RX CH wrap around happen and No RX free frame
       * RX side should wait till new free frame available in the pool
       * Do not try reload driver at here*/
      if(!(chStat & WLANDXE_CH_CTRL_EN_MASK))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXFrameReady %s RING Wrapped, RX Free Low 0x%x",
                  channelType[channelEntry->channelType], chStat);
         /* This is not empty interrupt case
          * If handle this as empty interrupt, false SSR might be issued
          * Frame count '1' is dummy frame count to avoid SSR */
         channelEntry->numFragmentCurrentChain = 1;
         return eWLAN_PAL_STATUS_SUCCESS;
      }

      currentCtrlBlk = channelEntry->headCtrlBlk;
      currentDesc    = currentCtrlBlk->linkedDesc;
      descCtrl       = currentDesc->descCtrl.ctrl;

      if(WLANDXE_POWER_STATE_BMPS != dxeCtxt->hostPowerState)
      {
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
                   "RX ISR called but no frame handled PWS %d, channel %s",
                   (int)dxeCtxt->hostPowerState,
                   channelType[channelEntry->channelType]);
      }

      /* Current interupt empty and previous interrupt also empty
       * detected successive empty interrupt
       * or first interrupt empty, this should not happen */
      if(0 == channelEntry->numFragmentCurrentChain)
      {
         dxeChannelMonitor("RX Ready", channelEntry, NULL);
         dxeDescriptorDump(channelEntry, channelEntry->headCtrlBlk->linkedDesc, 0);
         dxeChannelRegisterDump(channelEntry, "RX successive empty interrupt", NULL);
         dxeChannelAllDescDump(channelEntry, channelEntry->channelType, NULL);
         /* Abnormal interrupt detected, try to find not validated descriptor */
         for(descLoop = 0; descLoop < channelEntry->numDesc; descLoop++)
         {
            if(!(WLANDXE_U32_SWAP_ENDIAN(descCtrl) & WLANDXE_DESC_CTRL_VALID))
            {
               HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                        "Found Invalidated Descriptor %d", (int)descLoop);
               if(eWLAN_PAL_STATUS_SUCCESS == wpalIsPacketLocked(currentCtrlBlk->xfrFrame))
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                           "Packet locked, Resync Host and HW");
                  channelEntry->headCtrlBlk = currentCtrlBlk;
                  invalidatedFound = 1;
                  break;
               }
               else
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                           "Packet Not Locked, cannot transfer frame");
               }
            }
            currentCtrlBlk = (WLANDXE_DescCtrlBlkType *)currentCtrlBlk->nextCtrlBlk;
            currentDesc    = currentCtrlBlk->linkedDesc;
            descCtrl       = currentDesc->descCtrl.ctrl;
         }

         /* Invalidated descriptor found, and that is not head descriptor
          * This means HW/SW descriptor miss match happen, and we may recover with just resync
          * Try re-sync here */
         if((invalidatedFound) && (0 != descLoop))
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "Found New Sync location with HW, handle frames from there");
            frameCount = dxeRXFrameRouteUpperLayer(dxeCtxt, channelEntry);
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "re-sync routed %d frames to upper layer", (int)frameCount);
            channelEntry->numFragmentCurrentChain = frameCount;
         }
         /* Successive Empty interrupt
          * But this case, first descriptor also invalidated, then it means head descriptor 
          * is linked with already handled RX frame, then could not unlock RX frame
          * This is just Out of RX buffer pool, not need to anything here */
         else if((invalidatedFound) && (0 == descLoop))
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "Out of RX Low resource, and INT came in, do nothing till get RX resource");
         }
         /* Critical error, reload driver */
         else
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "Could not found invalidated descriptor");
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "RX successive empty interrupt, Could not find invalidated DESC reload driver");
            dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
            wpalWlanReload(VOS_DXE_FAILURE);
            dxeStartSSRTimer(dxeCtxt);
         }
      }
   }
   channelEntry->numFragmentCurrentChain = frameCount;
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      dxeNotifySmsm

  @  Description: Notify SMSM to start DXE engine and/or condition of Tx ring
  buffer 

  @  Parameters

  @  Return
      wpt_status

===========================================================================*/
static wpt_status dxeNotifySmsm
(
  wpt_boolean kickDxe,
  wpt_boolean ringEmpty
)
{
   wpt_uint32 clrSt = 0;
   wpt_uint32 setSt = 0;

   if(kickDxe)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED, "Kick off DXE");

     if(tempDxeCtrlBlk->lastKickOffDxe == 0)
     {
       setSt |= WPAL_SMSM_WLAN_TX_ENABLE; 
       tempDxeCtrlBlk->lastKickOffDxe = 1;
     }
     else if(tempDxeCtrlBlk->lastKickOffDxe == 1)
     {
       clrSt |= WPAL_SMSM_WLAN_TX_ENABLE;
       tempDxeCtrlBlk->lastKickOffDxe = 0;
     }
     else
     {
       HDXE_ASSERT(0);
     }
   }
   else
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED, "no need to kick off DXE");
   }

   tempDxeCtrlBlk->txRingsEmpty = ringEmpty;
   if(ringEmpty)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED, "SMSM Tx Ring Empty");
     clrSt |= WPAL_SMSM_WLAN_TX_RINGS_EMPTY; 
   }
   else
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED, "SMSM Tx Ring Not Empty");
     setSt |= WPAL_SMSM_WLAN_TX_RINGS_EMPTY; 
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH, "C%x S%x", clrSt, setSt);

   /* Store the smsm notification sent to firmware */
   tempDxeCtrlBlk->smsmDxeHistogram = (tempDxeCtrlBlk->smsmDxeHistogram << 1);
   if(setSt & WPAL_SMSM_WLAN_TX_ENABLE)
   {
      tempDxeCtrlBlk->smsmDxeHistogram |= 1;
   }
   else
   {
      tempDxeCtrlBlk->smsmDxeHistogram &= ~((wpt_uint32)1);
   }
   tempDxeCtrlBlk->smsmRingsEmptyHistogram = (tempDxeCtrlBlk->smsmRingsEmptyHistogram << 1);
   if(setSt & WPAL_SMSM_WLAN_TX_RINGS_EMPTY)
   {
      tempDxeCtrlBlk->smsmRingsEmptyHistogram |= 1;
   }
   else
   {
      tempDxeCtrlBlk->smsmRingsEmptyHistogram &= ~((wpt_uint32)1);
   }
   wpalNotifySmsm(clrSt, setSt);

   return eWLAN_PAL_STATUS_SUCCESS;
}

/*==========================================================================
  @  Function Name 
      dxePsComplete

  @  Description: Utility function to check the resv desc to deside if we can
  get into Power Save mode now 

  @  Parameters

  @  Return
      None

===========================================================================*/
static void dxePsComplete(WLANDXE_CtrlBlkType *dxeCtxt, wpt_boolean intr_based)
{
   if( dxeCtxt->hostPowerState == WLANDXE_POWER_STATE_FULL )
   {
     return;
   }

   //if both HIGH & LOW Tx channels don't have anything on resv desc,all Tx pkts
   //must have been consumed by RIVA, OK to get into BMPS
   if((0 == dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].numRsvdDesc) &&
      (0 == dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].numRsvdDesc))
   {
      tempDxeCtrlBlk->ringNotEmpty = eWLAN_PAL_FALSE;
      //if host is in BMPS & no pkt to Tx, RIVA can go to power save
      if(WLANDXE_POWER_STATE_BMPS == dxeCtxt->hostPowerState)
      {
         dxeCtxt->rivaPowerState = WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN;
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
      }
   }
   else //still more pkts to be served by RIVA
   {
      tempDxeCtrlBlk->ringNotEmpty = eWLAN_PAL_TRUE;

      switch(dxeCtxt->rivaPowerState)
      {
         case WLANDXE_RIVA_POWER_STATE_ACTIVE:
            //NOP
            break;
         case WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN:
            if(intr_based)
            {
               dxeCtxt->rivaPowerState = WLANDXE_RIVA_POWER_STATE_ACTIVE;
               dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
            }
            break;
         default:
            //assert
            break;
      }
   }
}

/*==========================================================================
  @  Function Name 
      dxeRXEventHandler

  @  Description 
      Handle serailized RX frame ready event
      First disable interrupt then pick up frame from pre allocated buffer
      Since frame handle is doen, clear interrupt bit to ready next interrupt
      Finally re enable interrupt

  @  Parameters
      wpt_msg   *rxReadyMsg
                 RX frame ready MSG pointer
                 include DXE control context

  @  Return
      NONE

===========================================================================*/
void dxeRXEventHandler
(
   wpt_msg                 *rxReadyMsg
)
{
   wpt_msg                  *msgContent = (wpt_msg *)rxReadyMsg;
   WLANDXE_CtrlBlkType      *dxeCtxt    = NULL;
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                intSrc     = 0;
   WLANDXE_ChannelCBType    *channelCb  = NULL;
   wpt_uint32                chHighStat = 0;
   wpt_uint32                chLowStat  = 0;
   wpt_uint32                chLogRxStat  = 0;
   wpt_uint32                chLogRxFwStat = 0;
   wpt_uint32                regValue, chanMask;

   dxeCtxt = (WLANDXE_CtrlBlkType *)(msgContent->pContext);

   if(eWLAN_PAL_TRUE == dxeCtxt->driverReloadInProcessing)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "RX Ready WLAN Driver re-loading in progress");
      return;
   }

   /* Now try to refill the ring with empty Rx buffers to keep DXE busy */
   dxeRXFrameRefillRing(dxeCtxt, &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI]);
   dxeRXFrameRefillRing(dxeCtxt, &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI]);
   if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG))
      dxeRXFrameRefillRing(dxeCtxt, &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG]);
      
   if((!dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].extraConfig.chEnabled) ||
      (!dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].extraConfig.chEnabled) ||
      (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG) &&
       !dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].extraConfig.chEnabled))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
         "DXE already stopped in RX event handler. Just return");
      return;
   }

   /* Disable device interrupt */
   /* Read whole interrupt mask register and exclusive only this channel int */
   status = wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS,
                              &intSrc);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXEventHandler Read INT_SRC register fail");
      return;
   }
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED,
            "RX Event Handler INT Source 0x%x", intSrc);

   dxeEnvBlk.rxIntChanlSrc = intSrc&0xFF;

   if((WLANDXE_POWER_STATE_IMPS == dxeCtxt->hostPowerState) ||
      (WLANDXE_POWER_STATE_DOWN == dxeCtxt->hostPowerState))
   {
      if (WLANDXE_POWER_STATE_DOWN != dxeCtxt->hostPowerState)
      {
        if(0 == intSrc)
        {
           HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "%s: Read status: %d, regVal: %d",
                    __func__, status, intSrc);
        }
        else
        {
           /* Register Read was succesful and we have a valid interrupt
            * source, so WCN is not power collapsed yet and it should
            * not power collapse till we set the synchronization bit
            * at the end of this function, safe to pull frames...
            */
            goto pull_frames;
        }
      }

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
         "%s Riva is in %d, Just Pull frames without any register touch",
           __func__, dxeCtxt->hostPowerState);

      /* Not to touch any register, just pull frame directly from chain ring
       * First high priority */
      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI];
      status = dxeRXFrameReady(dxeCtxt,
                               channelCb,
                               chHighStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXEventHandler Pull from RX high channel fail");
      }
      /* In case FW could not power collapse in IMPS mode
       * Next power restore might have empty interrupt
       * If IMPS mode has empty interrupt since RX thread race,
       * Invalid re-load driver might happen
       * To prevent invalid re-load driver,
       * IMPS event handler set dummpy frame count */
      channelCb->numFragmentCurrentChain = 1;

       /* Second low priority */
      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI];
      status = dxeRXFrameReady(dxeCtxt,
                               channelCb,
                               chLowStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXEventHandler Pull from RX low channel fail");
      }
      /* LOW Priority CH same above */
      channelCb->numFragmentCurrentChain = 1;

      if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG))
      {
         channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG];
         status = dxeRXFrameReady(dxeCtxt,
                                  channelCb,
                                  chLogRxStat);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeRXEventHandler Pull from RX log channel fail");
         }
         channelCb->numFragmentCurrentChain = 1;
      }
      /* Interrupt will not enabled at here, it will be enabled at PS mode change */
      tempDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_TRUE;
      dxeEnvBlk.rxIntDisableReturn = VOS_RETURN_ADDRESS;
      dxeEnvBlk.rxIntDisableFrame = __builtin_frame_address(0);
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
            "%s Host is in %d RX Int Disabled",
            __func__, dxeCtxt->hostPowerState);
      return;
   }

pull_frames:
   /* Test High Priority Channel interrupt is enabled or not */
   channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI];
   if(intSrc & (1 << channelCb->assignedDMAChannel))
   {
      status = dxeChannelCleanInt(channelCb, &chHighStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXEventHandler INT Clean up fail");
         return;         
      }
      if(WLANDXE_CH_STAT_INT_ERR_MASK & chHighStat)
      {
         /* Error Happen during transaction, Handle it */
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%11s : 0x%x Error Reported, Reload Driver",
                  channelType[channelCb->channelType], chHighStat);

         if (eWLAN_PAL_STATUS_SUCCESS != dxeErrHandler(channelCb, chHighStat))
         {
            dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
            wpalWlanReload(VOS_DXE_FAILURE);
            dxeStartSSRTimer(dxeCtxt);
         }
      }
      else if((WLANDXE_CH_STAT_INT_DONE_MASK & chHighStat) ||
              (WLANDXE_CH_STAT_INT_ED_MASK & chHighStat))
      {
         /* Handle RX Ready for high priority channel */
         status = dxeRXFrameReady(dxeCtxt,
                                  channelCb,
                                  chHighStat);
      }
      else if(WLANDXE_CH_STAT_MASKED_MASK & chHighStat)
      {
         status = dxeRXFrameReady(dxeCtxt,
                                  channelCb,
                                  chHighStat);
      }
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
               "RX HIGH CH EVNT STAT 0x%x, %d frames handled", chHighStat, channelCb->numFragmentCurrentChain);
      /* Update the Rx DONE histogram */
      channelCb->rxDoneHistogram = (channelCb->rxDoneHistogram << 1);
      if(WLANDXE_CH_STAT_INT_DONE_MASK & chHighStat)
      {
         channelCb->rxDoneHistogram |= 1;
      }
      else
      {
         channelCb->rxDoneHistogram &= ~((wpt_uint64)1);
      }
   }

   /* Test Low Priority Channel interrupt is enabled or not */
       channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI];
   if(intSrc & (1 << channelCb->assignedDMAChannel))
   {
      status = dxeChannelCleanInt(channelCb, &chLowStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXEventHandler INT Clean up fail");
         return;         
      }

      if(WLANDXE_CH_STAT_INT_ERR_MASK & chLowStat)
      {
         /* Error Happen during transaction, Handle it */
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%11s : 0x%x Error Reported, Reload Driver",
                  channelType[channelCb->channelType], chLowStat);

         if (eWLAN_PAL_STATUS_SUCCESS !=
                         dxeErrHandler(channelCb, chLowStat))
         {
            dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
            wpalWlanReload(VOS_DXE_FAILURE);
            dxeStartSSRTimer(dxeCtxt);
         }
      }
      else if((WLANDXE_CH_STAT_INT_ED_MASK & chLowStat) ||
               (WLANDXE_CH_STAT_INT_DONE_MASK & chLowStat))
      {
         /* Handle RX Ready for low priority channel */
         status = dxeRXFrameReady(dxeCtxt,
                                  channelCb,
                                  chLowStat);
       }

      /* Update the Rx DONE histogram */
      channelCb->rxDoneHistogram = (channelCb->rxDoneHistogram << 1);
      if(WLANDXE_CH_STAT_INT_DONE_MASK & chLowStat)
      {
         channelCb->rxDoneHistogram |= 1;
      }
      else
      {
         channelCb->rxDoneHistogram &= ~((wpt_uint64)1);
      }
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
               "RX LOW CH EVNT STAT 0x%x, %d frames handled", chLowStat, channelCb->numFragmentCurrentChain);
   }

   if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG))
   {
      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG];

      if(intSrc & (1 << channelCb->assignedDMAChannel))
      {
         status = dxeChannelCleanInt(channelCb,&chLogRxStat);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeRXEventHandler INT Clean up fail");
            return;
         }

         if(WLANDXE_CH_STAT_INT_ERR_MASK & chLogRxStat)
         {
            /* Error Happen during transaction, Handle it */
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%11s : 0x%x Error Reported, Reload Driver",
                     channelType[channelCb->channelType], chLogRxStat);

            if (eWLAN_PAL_STATUS_SUCCESS !=
                            dxeErrHandler(channelCb, chLogRxStat))
            {
               dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
               wpalWlanReload(VOS_DXE_FAILURE);
               dxeStartSSRTimer(dxeCtxt);
            }

         }
         else if((WLANDXE_CH_STAT_INT_ED_MASK & chLogRxStat) ||
                  (WLANDXE_CH_STAT_INT_DONE_MASK & chLogRxStat))
         {
            /* Handle RX Ready for low priority channel */
            status = dxeRXFrameReady(dxeCtxt,
                                     channelCb,
                                     chLogRxStat);
          }

         /* Update the Rx DONE histogram */
         channelCb->rxDoneHistogram = (channelCb->rxDoneHistogram << 1);
         if(WLANDXE_CH_STAT_INT_DONE_MASK & chLogRxStat)
         {
            channelCb->rxDoneHistogram |= 1;
         }
         else
         {
            channelCb->rxDoneHistogram &= ~1;
         }
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                  "RX LOG CH EVNT STAT 0x%x, %d frames handled", chLogRxStat, channelCb->numFragmentCurrentChain);
      }
   }

   if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_FW_LOG))
   {
      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_FW_LOG];

      if(intSrc & (1 << channelCb->assignedDMAChannel))
      {
         status = dxeChannelCleanInt(channelCb,&chLogRxFwStat);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeRXEventHandler INT Clean up fail");
            return;
         }

         if(WLANDXE_CH_STAT_INT_ERR_MASK & chLogRxFwStat)
         {
            /* Error Happen during transaction, Handle it */
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%11s : 0x%x Error Reported, Reload Driver",
                     channelType[channelCb->channelType], chLogRxFwStat);

            if (eWLAN_PAL_STATUS_SUCCESS !=
                            dxeErrHandler(channelCb, chLogRxFwStat))
            {
               dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
               wpalWlanReload(VOS_DXE_FAILURE);
               dxeStartSSRTimer(dxeCtxt);
            }

         }
         else if((WLANDXE_CH_STAT_INT_ED_MASK & chLogRxFwStat) ||
                 (WLANDXE_CH_STAT_INT_DONE_MASK & chLogRxFwStat))
         {
            if (!dxeCtxt->hostInitiatedH2H)
            {
               dxeCtxt->receiveMbMsgCB(dxeCtxt->clientCtxt);
            }
            else
            {
               status = dxeRXFrameReady(dxeCtxt,
                                        channelCb,
                                        chLogRxFwStat);
               if (channelCb->numFreeDesc == channelCb->numDesc)
               {
                  /*
                   * We have already cleared the interrupts before coming here,
                   * but it can happen that DXE will copy some new packets after
                   * that and raise interrupts for those. The packets will be
                   * processed above but the interrupts will still be pending.
                   * Its safe to clear those interrupts here because we have
                   * pulled data from all the allocated descriptors.
                   */
                  dxeChannelCleanInt(channelCb,&chLogRxFwStat);
                  dxeCtxt->hostInitiatedH2H = 0;
                  dxeCtxt->receiveLogCompleteCB(dxeCtxt->clientCtxt);
               }
            }
         }

         /* Update the Rx DONE histogram */
         channelCb->rxDoneHistogram = (channelCb->rxDoneHistogram << 1);
         if(WLANDXE_CH_STAT_INT_DONE_MASK & chLogRxFwStat)
         {
            channelCb->rxDoneHistogram |= 1;
         }
         else
         {
            channelCb->rxDoneHistogram &= ~1;
         }
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                  "RX LOG CH EVNT STAT 0x%x, %d frames handled", chLogRxFwStat, channelCb->numFragmentCurrentChain);
      }
   }
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXEventHandler Handle Frame Ready Fail");
      return;         
   }

   /* Prepare Control Register EN Channel */
   if(!(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].extraConfig.chan_mask & WLANDXE_CH_CTRL_EN_MASK))
   {
      HDXE_ASSERT(0);
   }

   if (dxeCtxt->rxPalPacketUnavailable &&
       (WLANDXE_CH_STAT_INT_DONE_MASK & chHighStat))
   {
     chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].extraConfig.chan_mask &
                (~WLANDXE_CH_CTRL_INE_DONE_MASK);
     dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].doneIntDisabled = 1;
   }
   else
   {
     chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].extraConfig.chan_mask;
     dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].doneIntDisabled = 0;
   }
   wpalWriteRegister(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI].channelRegister.chDXECtrlRegAddr,
                     chanMask);

   /* Prepare Control Register EN Channel */
   if(!(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].extraConfig.chan_mask & WLANDXE_CH_CTRL_EN_MASK))
   {
      HDXE_ASSERT(0);
   }

   if (dxeCtxt->rxPalPacketUnavailable &&
       (WLANDXE_CH_STAT_INT_DONE_MASK & chLowStat))
   {
     chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].extraConfig.chan_mask &
                (~WLANDXE_CH_CTRL_INE_DONE_MASK);
     dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].doneIntDisabled = 1;
   }
   else
   {
     chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].extraConfig.chan_mask;
     dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].doneIntDisabled = 0;
   }
   wpalWriteRegister(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI].channelRegister.chDXECtrlRegAddr,
                     chanMask);

   /* We do not have knowledge of firmare capabilities when the
    * RX_LOG channel is enabled. But when we get the first interrupt
    * we have all the required information. So if MGMT Logging is not
    * supported by the firmware, do not re-enable RX_LOG channel
    */
   if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG) && wpalIsFwLoggingSupported())
   {
      if(!(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].extraConfig.chan_mask & WLANDXE_CH_CTRL_EN_MASK))
      {
         HDXE_ASSERT(0);
      }

      if (dxeCtxt->rxPalPacketUnavailable &&
          (WLANDXE_CH_STAT_INT_DONE_MASK & chLogRxStat))
      {
        chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].extraConfig.chan_mask &
                   (~WLANDXE_CH_CTRL_INE_DONE_MASK);
        dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].doneIntDisabled = 1;
      }
      else
      {
        chanMask = dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].extraConfig.chan_mask;
        dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].doneIntDisabled = 0;
      }
      wpalWriteRegister(dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG].channelRegister.chDXECtrlRegAddr,
                        chanMask);
   }

   /* Clear Interrupt handle processing bit
    * RIVA may power down */
   if (!(wpalIsFwLoggingSupported() && wpalIsFwLoggingEnabled()))
   {
      wpalReadRegister(WLANDXE_INT_MASK_REG_ADDRESS, &regValue);
      regValue &= WLANDXE_RX_INTERRUPT_PRO_UNMASK;
      wpalWriteRegister(WLANDXE_INT_MASK_REG_ADDRESS, regValue);
   }
   else
   {
      wpalReadRegister(WLAN_PMU_SPARE_OUT_ADDRESS, &regValue);
      regValue &= (~WLAN_PMU_POWER_DOWN_MASK);
      wpalWriteRegister(WLAN_PMU_SPARE_OUT_ADDRESS, regValue);
   }

   dxeEnvBlk.rxIntChanlSrc = 0;

   /* Enable system level ISR */
   /* Enable RX ready Interrupt at here */
   status = wpalEnableInterrupt(DXE_INTERRUPT_RX_READY);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXEventHandler Enable RX Ready interrupt fail");
      return;
   }
   DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_RXINT_STATE,
                    TRACE_WLANDXE_VAR_ENABLE));
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}

/*==========================================================================
  @  Function Name 
      dxeRXPacketAvailableEventHandler

  @  Description 
      Handle serialized RX Packet Available event when the corresponding callback
      is invoked by WPAL.
      Try to fill up any completed DXE descriptors with available Rx packet buffer
      pointers.

  @  Parameters
      wpt_msg   *rxPktAvailMsg
                 RX frame ready MSG pointer
                 include DXE control context

  @  Return
      NONE

===========================================================================*/
void dxeRXPacketAvailableEventHandler
(
   wpt_msg                 *rxPktAvailMsg
)
{
   WLANDXE_CtrlBlkType      *dxeCtxt    = NULL;
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_ChannelCBType    *channelCb  = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity Check */
   if(NULL == rxPktAvailMsg)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXPacketAvailableEventHandler Context is not valid");
      return;
   }

   dxeCtxt    = (WLANDXE_CtrlBlkType *)(rxPktAvailMsg->pContext);

#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
   /* Available resource allocated
    * Stop timer not needed */
   if(VOS_TIMER_STATE_RUNNING ==
      wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer))
   {
      wpalTimerStop(&dxeCtxt->rxResourceAvailableTimer);
      dxeEnvBlk.rx_low_resource_timer = 0;
   }
#endif

   do
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "dxeRXPacketAvailableEventHandler, start refilling ring");

      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_HIGH_PRI];
      status = dxeRXFrameRefillRing(dxeCtxt,channelCb);
   
      // Wait for another callback to indicate when Rx resources are available
      // again.
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         break;
      }
   
      channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOW_PRI];
      status = dxeRXFrameRefillRing(dxeCtxt,channelCb);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         break;
      }

      if (WLANDXE_IS_VALID_CHANNEL(WDTS_CHANNEL_RX_LOG))
      {
         channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_RX_LOG];
         status = dxeRXFrameRefillRing(dxeCtxt,channelCb);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            break;
         }
      }
   } while(0);

   if((WLANDXE_POWER_STATE_IMPS == dxeCtxt->hostPowerState) ||
      (WLANDXE_POWER_STATE_DOWN == dxeCtxt->hostPowerState))
   {
      /* Interrupt will not enabled at here, it will be enabled at PS mode change */
      tempDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_TRUE;
      dxeEnvBlk.rxIntDisableReturn = VOS_RETURN_ADDRESS;
      dxeEnvBlk.rxIntDisableFrame = __builtin_frame_address(0);
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
            "dxeRXPacketAvailableEventHandler Int Disabled by IMPS");
   }
}

/*==========================================================================
  @  Function Name 
      dxeRXISR

  @  Description 
      RX frame ready interrupt service routine
      interrupt entry function, this function called based on ISR context
      Must be serialized

  @  Parameters
      void    *hostCtxt
               DXE host driver control context,
               pre registerd during interrupt registration

  @  Return
      NONE

===========================================================================*/
static void dxeRXISR
(
   void                    *hostCtxt
)
{
   WLANDXE_CtrlBlkType      *dxeCtxt    = (WLANDXE_CtrlBlkType *)hostCtxt;
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                regValue;
   wpt_uint32                intSrc     = 0;

   /* Set Interrupt processing bit
    * During this bit set, WLAN HW may not power collapse */
   if (!(wpalIsFwLoggingSupported() && wpalIsFwLoggingEnabled()))
   {
      wpalReadRegister(WLANDXE_INT_MASK_REG_ADDRESS, &regValue);
      regValue |= WLANPAL_RX_INTERRUPT_PRO_MASK;
      wpalWriteRegister(WLANDXE_INT_MASK_REG_ADDRESS, regValue);
   }
   else
   {
      wpalReadRegister(WLAN_PMU_SPARE_OUT_ADDRESS, &regValue);
      regValue |= WLAN_PMU_POWER_DOWN_MASK;
      wpalWriteRegister(WLAN_PMU_SPARE_OUT_ADDRESS, regValue);
   }

   /* Disable interrupt at here
    * Disable RX Ready system level Interrupt at here
    * Otherwise infinite loop might happen */
   status = wpalDisableInterrupt(DXE_INTERRUPT_RX_READY);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameReadyISR Disable RX ready interrupt fail");
      return;         
   }

   status = wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS,
                                  &intSrc);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      status = wpalEnableInterrupt(DXE_INTERRUPT_RX_READY);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                   "dxeISR enable rx ready interrupt fail");
      return;
   }
   /* Note: intSrc which holds the INT_SRC_RAW_ADDRESS reg value
      While debugging crash dump convert to power of 2 for channel type */
   DXTRACE(dxeTrace(intSrc, TRACE_RXINT_STATE, TRACE_WLANDXE_VAR_DISABLE));

   /* Serialize RX Ready interrupt upon RX thread */
   if(NULL == dxeCtxt->rxIsrMsg)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeRXFrameReadyISR NULL message");
      HDXE_ASSERT(0);
      return;
   }

   status = wpalPostRxMsg(WDI_GET_PAL_CTX(),
                          dxeCtxt->rxIsrMsg);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "dxeRXFrameReadyISR interrupt serialize fail");
   }

   return;
}

/*==========================================================================
  @  Function Name 
      dxeTXPushFrame

  @  Description
      Push TX frame into DXE descriptor and DXE register
      Send notification to DXE register that TX frame is ready to transfer

  @  Parameters
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block
      wpt_packet              *palPacket
                               Packet pointer ready to transfer

  @  Return
      PAL_STATUS_T
===========================================================================*/
static wpt_status dxeTXPushFrame
(
   WLANDXE_ChannelCBType   *channelEntry,
   wpt_packet              *palPacket
)
{
   wpt_status                  status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType    *currentCtrlBlk = NULL;
   WLANDXE_DescCtrlBlkType    *tailCtrlBlk    = NULL;
   WLANDXE_DescType           *currentDesc    = NULL;
   WLANDXE_DescType           *firstDesc      = NULL;
   WLANDXE_DescType           *LastDesc       = NULL;
   WLANDXE_DescType           *tailDesc       = NULL;
   void                       *sourcePhysicalAddress = NULL;
   wpt_uint32                  xferSize = 0;
   wpt_iterator                iterator;
   wpt_uint8                   KickDxe   = 0;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   tempDxeCtrlBlk->smsmToggled = eWLAN_PAL_FALSE;
   if((0 == tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].numRsvdDesc) &&
      (0 == tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].numRsvdDesc))
   {
       KickDxe = 1;
   }

   /* Kick DXE when the ring is about to fill */
   if (WLANDXE_TX_LOW_RES_THRESHOLD >= channelEntry->numFreeDesc)
   {
       KickDxe = 1;
       tailCtrlBlk = channelEntry->tailCtrlBlk;
       tailDesc = tailCtrlBlk->linkedDesc;

       if(tailDesc->descCtrl.ctrl& WLANDXE_DESC_CTRL_VALID)
       {
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                   "dxeTXPushFrame Descs threshold reached No DMA");
       }
   }

   channelEntry->numFragmentCurrentChain = 0;
   currentCtrlBlk = channelEntry->headCtrlBlk;

   /* Initialize interator, TX is fragmented */
   status = wpalLockPacketForTransfer(palPacket);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame unable to lock packet");
      return status;
   }

   status = wpalIteratorInit(&iterator, palPacket);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame iterator init fail");
      return status;
   }

   /* !!!! Revisit break condition !!!!!!! */
   while(1)
   {
      /* Get current descriptor pointer from current control block */
      currentDesc = currentCtrlBlk->linkedDesc;
      if(NULL == firstDesc)
      {
         firstDesc = currentCtrlBlk->linkedDesc;
      }
      /* All control block will have same palPacket Pointer
       * to make logic simpler */
      currentCtrlBlk->xfrFrame = palPacket;

      /* Get next fragment physical address and fragment size
       * if this is the first trial, will get first physical address
       * if no more fragment, Descriptor src address will be set as NULL, OK??? */
      status = wpalIteratorNext(&iterator,
                                palPacket,
                                &sourcePhysicalAddress,
                                &xferSize);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame Get next frame fail");
         return status;
      }
      if((NULL == sourcePhysicalAddress) ||
         (0    == xferSize))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
                  "dxeTXPushFrame end of current frame");
         break;
      }

      /* This is the LAST descriptor valid for this transaction */
      LastDesc    = currentCtrlBlk->linkedDesc;

      /* Program DXE descriptor */
      currentDesc->dxedesc.dxe_short_desc.srcMemAddrL =
                               WLANDXE_U32_SWAP_ENDIAN((wpt_uint32)(uintptr_t)sourcePhysicalAddress);

      /* Just normal data transfer from aCPU Flat Memory to BMU Q */
      if((WDTS_CHANNEL_TX_LOW_PRI  == channelEntry->channelType) ||
         (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
      {
         currentDesc->dxedesc.dxe_short_desc.dstMemAddrL =
                                WLANDXE_U32_SWAP_ENDIAN(channelEntry->channelConfig.refWQ);
      }
      else
      {
         /* Test specific H2H transfer, destination address already set
          * Do Nothing */
      }
      currentDesc->xfrSize = WLANDXE_U32_SWAP_ENDIAN(xferSize);

      /* Program channel control register */
      /* First frame not set VAL bit, why ??? */
      if(0 == channelEntry->numFragmentCurrentChain)
      {
         currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_write;
      }
      else
      {
         currentDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_write_valid;
      }

      /* Update statistics */
      channelEntry->numFragmentCurrentChain++;
      channelEntry->numFreeDesc--;
      channelEntry->numRsvdDesc++;

      /* Get next control block */
      currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
   }
   channelEntry->numTotalFrame++;
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "NUM TX FRAG %d, Total Frame %d",
            channelEntry->numFragmentCurrentChain, channelEntry->numTotalFrame);

   /* Program Channel control register
    * Set as end of packet
    * Enable interrupt also for first code lock down
    * performace optimization, this will be revisited */
   if(NULL == LastDesc)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame NULL Last Descriptor, broken chain");
      return eWLAN_PAL_STATUS_E_FAULT;
   }
   LastDesc->descCtrl.ctrl  = channelEntry->extraConfig.cw_ctrl_write_eop_int;
   /* Now First one also Valid ????
    * this procedure will prevent over handle descriptor from previous
    * TX trigger */
   firstDesc->descCtrl.ctrl = channelEntry->extraConfig.cw_ctrl_write_valid;

   /* If in BMPS mode no need to notify the DXE Engine, notify SMSM instead */
   if(WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN == tempDxeCtrlBlk->rivaPowerState)
   {
      /* Update channel head as next avaliable linked slot */
      channelEntry->headCtrlBlk = currentCtrlBlk;
      if(KickDxe)
      {
         tempDxeCtrlBlk->ringNotEmpty = eWLAN_PAL_TRUE;
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
                  "SMSM_ret LO=%d HI=%d",
                  tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].numRsvdDesc,
                  tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].numRsvdDesc );
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
         tempDxeCtrlBlk->smsmToggled = eWLAN_PAL_TRUE;
         DXTRACE(dxeTrace(channelEntry->channelType, TRACE_SMSM_NOTIFY, TRACE_WLANDXE_VAR_ENABLE));
      }
      return status;
   }

   /* If DXE use external descriptor, registers are not needed to be programmed
    * Just after finish to program descriptor, tirigger to send */
   if(channelEntry->extraConfig.chan_mask & WLANDXE_CH_CTRL_EDEN_MASK)
   {
      /* Issue a dummy read from the DXE descriptor DDR location to
         ensure that any previously posted write to the descriptor
         completes. */
      if(channelEntry->extraConfig.cw_ctrl_write_valid != firstDesc->descCtrl.ctrl)
      {
         //HDXE_ASSERT(0);
      }

      if(wpalIsArpPkt(palPacket))
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH,
                  "%s :ARP packet", __func__);
      }

      /* Everything is ready
       * Trigger to start DMA */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                                      channelEntry->extraConfig.chan_mask);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame Write Channel Ctrl Register fail");
         return status;
      }
      DXTRACE(dxeTrace(channelEntry->channelType, TRACE_CH_ENABLE, TRACE_WLANDXE_VAR_ENABLE));

      /* Update channel head as next avaliable linked slot */
      channelEntry->headCtrlBlk = currentCtrlBlk;

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
               "%s Exit", __func__);
      return status;
   }

   /* If DXE not use external descriptor, program each registers */
   /* Circular buffer handle not need to program DESC register???
    * GEN5 code not programed RING buffer case
    * REVISIT THIS !!!!!! */
   if((WDTS_CHANNEL_TX_LOW_PRI  == channelEntry->channelType) ||
      (WDTS_CHANNEL_TX_HIGH_PRI == channelEntry->channelType))
   {
      /* Destination address, assigned Work Q */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXEDadrlRegAddr,
                                      channelEntry->channelConfig.refWQ);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame Program dest address register fail");
         return status;
      }
      /* If descriptor format is SHORT */
      if(channelEntry->channelConfig.useShortDescFmt)
      {
         status = wpalWriteRegister(channelEntry->channelRegister.chDXEDadrhRegAddr,
                                         0);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeTXPushFrame Program dest address register fail");
            return status;
         }
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame LONG Descriptor Format!!!");
      }
   }

   /* Program Source address register
    * This address is already programmed into DXE Descriptor
    * But register also upadte */
   status = wpalWriteRegister(channelEntry->channelRegister.chDXESadrlRegAddr,
                                   WLANDXE_U32_SWAP_ENDIAN(firstDesc->dxedesc.dxe_short_desc.srcMemAddrL));
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame Program src address register fail");
      return status;
   }
   /* If descriptor format is SHORT */
   if(channelEntry->channelConfig.useShortDescFmt)
   {
      status = wpalWriteRegister(channelEntry->channelRegister.chDXESadrhRegAddr,
                                      0);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame Program dest address register fail");
         return status;
      }
   }
   else
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame LONG Descriptor Format!!!");
   }

   /* Linked list Descriptor pointer */
   status = wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                   channelEntry->headCtrlBlk->linkedDescPhyAddr);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame Write DESC Address register fail");
      return status;
   }
   /* If descriptor format is SHORT */
   if(channelEntry->channelConfig.useShortDescFmt)
   {
      status = wpalWriteRegister(channelEntry->channelRegister.chDXEDeschRegAddr,
                                      0);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXPushFrame Program dest address register fail");
         return status;
      }
   }
   else
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame LONG Descriptor Format!!!");
   }

   /* Transfer Size */
   xferSize = WLANDXE_U32_SWAP_ENDIAN(firstDesc->xfrSize);
   status = wpalWriteRegister(channelEntry->channelRegister.chDXESzRegAddr,
                                   xferSize);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame Write DESC Address register fail");
      return status;
   }

   /* Everything is ready
    * Trigger to start DMA */
   status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                                   channelEntry->extraConfig.chan_mask);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXPushFrame Write Channel Ctrl Register fail");
      return status;
   }

   /* Update channel head as next avaliable linked slot */
   channelEntry->headCtrlBlk = currentCtrlBlk;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      dxeTXCompFrame

  @  Description 
      TX Frame transfer complete event handler

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block
      WLANDXE_ChannelCBType   *channelEntry
                               Channel specific control block

  @  Return
      PAL_STATUS_T
===========================================================================*/
static wpt_status dxeTXCompFrame
(
   WLANDXE_CtrlBlkType     *hostCtxt,
   WLANDXE_ChannelCBType   *channelEntry
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   WLANDXE_DescType         *currentDesc    = NULL;
   wpt_uint32                descCtrlValue  = 0;
   unsigned int             *lowThreshold   = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if((NULL == hostCtxt) || (NULL == channelEntry))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompFrame Invalid ARG");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if(NULL == hostCtxt->txCompCB)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompFrame TXCompCB is not registered");
      return eWLAN_PAL_STATUS_SUCCESS;
   }

   status = wpalMutexAcquire(&channelEntry->dxeChannelLock);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompFrame Mutex Acquire fail");
      return status;
   }
   
   currentCtrlBlk = channelEntry->tailCtrlBlk;
   currentDesc    = currentCtrlBlk->linkedDesc;

   if( currentCtrlBlk == channelEntry->headCtrlBlk )
   {
      status = wpalMutexRelease(&channelEntry->dxeChannelLock);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXCompFrame Mutex Release fail");
         return status;
      }
      return eWLAN_PAL_STATUS_SUCCESS;
   }


   while(1)
   {
//      HDXE_ASSERT(WLAN_PAL_IS_STATUS_SUCCESS(WLAN_RivaValidateDesc(currentDesc)));
      descCtrlValue = currentDesc->descCtrl.ctrl;
      if((descCtrlValue & WLANDXE_DESC_CTRL_VALID))
      {
         /* caught up with head, bail out */
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED,
                  "dxeTXCompFrame caught up with head - next DESC has VALID set");
         break;
      }

      if(currentCtrlBlk->xfrFrame == NULL)
      {
          HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "Invalid transfer frame");
          HDXE_ASSERT(0);
          break;
      }
      channelEntry->numFreeDesc++;
      channelEntry->numRsvdDesc--;

      /* Send Frame TX Complete notification with frame start fragment location */
      if(WLANDXE_U32_SWAP_ENDIAN(descCtrlValue) & WLANDXE_DESC_CTRL_EOP)
      {
         hostCtxt->txCompletedFrames--;
         status = wpalUnlockPacket(currentCtrlBlk->xfrFrame);
         if (eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "dxeRXFrameReady unable to unlock packet");
            status = wpalMutexRelease(&channelEntry->dxeChannelLock);
            if(eWLAN_PAL_STATUS_SUCCESS != status)
            {
               HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                        "dxeTXCompFrame Mutex Release fail");
            }
            return status;
         }

         if(wpalIsArpPkt(currentCtrlBlk->xfrFrame))
         {
             HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH,
                      "%s :ARP packet DMA-ed ", __func__);
             wpalUpdateTXArpFWdeliveredStats();
         }

         hostCtxt->txCompCB(hostCtxt->clientCtxt,
                            currentCtrlBlk->xfrFrame,
                            eWLAN_PAL_STATUS_SUCCESS);
         channelEntry->numFragmentCurrentChain = 0;
      }
      currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
      currentDesc    = currentCtrlBlk->linkedDesc;

      /* Break condition
       * Head control block is the control block must be programed for the next TX
       * so, head control block is not programmed control block yet
       * if loop encounte head control block, stop to complete
       * in theory, COMP CB must be called already ??? */
      if(currentCtrlBlk == channelEntry->headCtrlBlk)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED,
                  "dxeTXCompFrame caught up with head ptr");
         break;
      }
      /* VALID Bit check ???? */
   }

   /* Tail and Head Control block must be same */
   channelEntry->tailCtrlBlk = currentCtrlBlk;

   lowThreshold = channelEntry->channelType == WDTS_CHANNEL_TX_LOW_PRI?
      &(hostCtxt->txCompInt.txLowResourceThreshold_LoPriCh):
      &(hostCtxt->txCompInt.txLowResourceThreshold_HiPriCh);

   /* If specific channel hit low resource condition send notification to upper layer */
   if((eWLAN_PAL_TRUE == channelEntry->hitLowResource) &&
      (channelEntry->numFreeDesc > *lowThreshold))
   {
      /* Change it back if we raised it for fetching a remaining packet from TL */
      if(WLANDXE_TX_LOW_RES_THRESHOLD > *lowThreshold)
      {
         *lowThreshold = WLANDXE_TX_LOW_RES_THRESHOLD;
      }

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "DXE TX %d channel recovered from low resource", channelEntry->channelType);
      hostCtxt->lowResourceCB(hostCtxt->clientCtxt,
                              channelEntry->channelType,
                              eWLAN_PAL_TRUE);
      channelEntry->hitLowResource = eWLAN_PAL_FALSE;
   }

   status = wpalMutexRelease(&channelEntry->dxeChannelLock);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompFrame Mutex Release fail");
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name
      dxeTXCleanup

  @  Description
      Cleanup the TX channels after DXE Error

  @  Parameters
      WLANDXE_CtrlBlkType     *dxeCtrlBlk,
                               DXE host driver main control block

  @  Return
      PAL_STATUS_T
===========================================================================*/
static wpt_status dxeTXCleanup
(
   WLANDXE_CtrlBlkType     *hostCtxt
)
{
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_DescCtrlBlkType  *currentCtrlBlk = NULL;
   WLANDXE_DescType         *currentDesc    = NULL;
   wpt_uint32                descCtrlValue  = 0;
   unsigned int             *lowThreshold   = NULL;
   unsigned int              idx;
   WLANDXE_ChannelCBType    *channelEntry;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if((NULL == hostCtxt))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "%s: Invalid ARG", __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if(NULL == hostCtxt->txCompCB)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "%s: TXCompCB is not registered",__func__);
      return eWLAN_PAL_STATUS_SUCCESS;
   }

   for(idx = 0; idx < WDTS_CHANNEL_MAX; idx++)
   {
      channelEntry = &tempDxeCtrlBlk->dxeChannel[idx];
      if(idx != WDTS_CHANNEL_TX_LOW_PRI && idx != WDTS_CHANNEL_TX_HIGH_PRI)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                  "%s: %11s continue",__func__,
                  channelType[channelEntry->channelType]);
          continue;
      }

      status = wpalMutexAcquire(&channelEntry->dxeChannelLock);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s: %11s Mutex Acquire fail",__func__,
                  channelType[channelEntry->channelType]);
         return status;
      }

      currentCtrlBlk = channelEntry->tailCtrlBlk;
      currentDesc    = currentCtrlBlk->linkedDesc;

      if( currentCtrlBlk == channelEntry->headCtrlBlk )
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                  "%s: %11s Head and Tail are Same",__func__,
                  channelType[channelEntry->channelType]);

         status = wpalMutexRelease(&channelEntry->dxeChannelLock);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "%s: %11s Mutex Release fail",__func__,
                     channelType[channelEntry->channelType]);
            return status;
         }
         continue;
      }

      while(1)
      {
         descCtrlValue = currentDesc->descCtrl.ctrl;
         if((descCtrlValue & WLANDXE_DESC_CTRL_VALID))
         {
             /* invalidate... */
             currentDesc->descCtrl.ctrl &= ~WLANDXE_DESC_CTRL_VALID;
         }

         if(currentCtrlBlk->xfrFrame == NULL)
         {
             HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "%s: %11s Invalid transfer frame",__func__,
                     channelType[channelEntry->channelType]);
             HDXE_ASSERT(0);
             break;
         }
         channelEntry->numFreeDesc++;
         channelEntry->numRsvdDesc--;

         /* Send Frame TX Complete notification with frame start fragment location */
         if(WLANDXE_U32_SWAP_ENDIAN(descCtrlValue) & WLANDXE_DESC_CTRL_EOP)
         {
            hostCtxt->txCompletedFrames--;
            status = wpalUnlockPacket(currentCtrlBlk->xfrFrame);
            if (eWLAN_PAL_STATUS_SUCCESS != status)
            {
               HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                        "%s: unable to unlock packet",__func__);
               status = wpalMutexRelease(&channelEntry->dxeChannelLock);
               if(eWLAN_PAL_STATUS_SUCCESS != status)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                           "%s: Mutex Release fail",__func__);
               }
               return status;
            }
            hostCtxt->txCompCB(hostCtxt->clientCtxt,
                               currentCtrlBlk->xfrFrame,
                               eWLAN_PAL_STATUS_SUCCESS); //mir: SUCCESS or FAILURE?
            channelEntry->numFragmentCurrentChain = 0;
         }
         currentCtrlBlk = currentCtrlBlk->nextCtrlBlk;
         currentDesc    = currentCtrlBlk->linkedDesc;

         /* Break condition
          * Head control block is the control block must be programed for the next TX
          * so, head control block is not programmed control block yet
          * if loop encounte head control block, stop to complete
          * in theory, COMP CB must be called already ??? */
         if(currentCtrlBlk == channelEntry->headCtrlBlk)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                     "%s: %11s caught up with head ptr",__func__,
                     channelType[channelEntry->channelType]);
            break;
         }
         /* VALID Bit check ???? */
      }

      /* Tail and Head Control block must be same */
      channelEntry->tailCtrlBlk = currentCtrlBlk;
      /* Re-Sync Head and CDR */
      status = wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                      channelEntry->headCtrlBlk->linkedDescPhyAddr);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeChannelInitProgram Write DESC Address register fail");
         status = wpalMutexRelease(&channelEntry->dxeChannelLock);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "%s: %11s Mutex Release fail", __func__,
                     channelType[channelEntry->channelType]);
         }
         return status;
      }

      lowThreshold = channelEntry->channelType == WDTS_CHANNEL_TX_LOW_PRI?
         &(hostCtxt->txCompInt.txLowResourceThreshold_LoPriCh):
         &(hostCtxt->txCompInt.txLowResourceThreshold_HiPriCh);

      /* If specific channel hit low resource condition send notification to upper layer */
      if((eWLAN_PAL_TRUE == channelEntry->hitLowResource) &&
         (channelEntry->numFreeDesc > *lowThreshold))
      {
         /* Change it back if we raised it for fetching a remaining packet from TL */
         if(WLANDXE_TX_LOW_RES_THRESHOLD > *lowThreshold)
         {
            *lowThreshold = WLANDXE_TX_LOW_RES_THRESHOLD;
         }

         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                  "DXE TX %d channel recovered from low resource", channelEntry->channelType);
         hostCtxt->lowResourceCB(hostCtxt->clientCtxt,
                                 channelEntry->channelType,
                                 eWLAN_PAL_TRUE);
         channelEntry->hitLowResource = eWLAN_PAL_FALSE;
      }
      status = wpalMutexRelease(&channelEntry->dxeChannelLock);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s: %11s Mutex Release fail", __func__,
                  channelType[channelEntry->channelType]);
      }
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}
/*==========================================================================
  @  Function Name 
      dxeTXEventHandler

  @  Description 
      If DXE HW sends TX related interrupt, this event handler will be called
      Handle higher priority channel first
      Figureout why interrupt happen and call appropriate final even handler
      TX complete or error happen

  @  Parameters
         void               *msgPtr
                             Even MSG

  @  Return
      PAL_STATUS_T
===========================================================================*/
void dxeTXEventHandler
(
   wpt_msg               *msgPtr
)
{
   wpt_msg                  *msgContent = (wpt_msg *)msgPtr;
   WLANDXE_CtrlBlkType      *dxeCtxt    = NULL;
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                intSrc     = 0;
   wpt_uint32                chStat     = 0;
   WLANDXE_ChannelCBType    *channelCb  = NULL;

   wpt_uint8                 bEnableISR = 0;
   static wpt_uint8          successiveIntWithIMPS;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   dxeCtxt = (WLANDXE_CtrlBlkType *)(msgContent->pContext);
   dxeCtxt->ucTxMsgCnt = 0;
   
   if(eWLAN_PAL_TRUE == dxeCtxt->driverReloadInProcessing)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "wlan: TX COMP WLAN Driver re-loading in progress");
      return;
   }

   /* Read whole interrupt mask register and exclusive only this channel int */
   status = wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS,
                                  &intSrc);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompleteEventHandler Read INT_DONE_SRC register fail");
      return;
   }
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_MED,
            "TX Event Handler INT Source 0x%x", intSrc);

   dxeEnvBlk.txCmpIntChanlSrc = intSrc&0xFF;

   /* Return from here if the RIVA is in IMPS, to avoid register access */
   if(WLANDXE_POWER_STATE_IMPS == dxeCtxt->hostPowerState)
   {
      successiveIntWithIMPS++;
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXEventHandler IMPS TX COMP INT successiveIntWithIMPS %d", successiveIntWithIMPS);
      status = dxeTXCompFrame(dxeCtxt, &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXEventHandler IMPS HC COMP interrupt fail");
      }

      status = dxeTXCompFrame(dxeCtxt, &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXEventHandler IMPS LC COMP interrupt fail");
      }

      if(((dxeCtxt->txCompletedFrames) &&
         (eWLAN_PAL_FALSE == dxeCtxt->txIntEnable)) &&
         (successiveIntWithIMPS == 1))
      {
         dxeCtxt->txIntEnable =  eWLAN_PAL_TRUE; 
         wpalEnableInterrupt(DXE_INTERRUPT_TX_COMPLE);
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                     "TX COMP INT Enabled, remain TX frame count on ring %d",
                     dxeCtxt->txCompletedFrames);

         dxeEnvBlk.txCmpIntChanlSrc = 0;

         /*Kicking the DXE after the TX Complete interrupt was enabled - to avoid 
           the posibility of a race*/
         dxePsComplete(dxeCtxt, eWLAN_PAL_TRUE);
      }
      else
      {
         dxeCtxt->txIntEnable =  eWLAN_PAL_FALSE;
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "TX COMP INT NOT Enabled, RIVA still wake up? remain TX frame count on ring %d, successiveIntWithIMPS %d",
                  dxeCtxt->txCompletedFrames, successiveIntWithIMPS);
      }
      return;
   }

   successiveIntWithIMPS = 0;
   if((!dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].extraConfig.chEnabled) ||
      (!dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].extraConfig.chEnabled))
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
         "DXE already stopped in TX event handler. Just return");
      return;
   }

   /* Test High Priority Channel is the INT source or not */
   channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI];
   if(intSrc & (1 << channelCb->assignedDMAChannel))
   {
      status = dxeChannelCleanInt(channelCb, &chStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXEventHandler INT Clean up fail");
         return;         
      }

      if(WLANDXE_CH_STAT_INT_ERR_MASK & chStat)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%11s : 0x%x Error Reported, Reload Driver",
                  channelType[channelCb->channelType], chStat);

         if (eWLAN_PAL_STATUS_SUCCESS !=
                         dxeErrHandler(channelCb, chStat))
         {
            dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
            wpalWlanReload(VOS_DXE_FAILURE);
            dxeStartSSRTimer(dxeCtxt);
         }
         bEnableISR = 1;
      }
      else if(WLANDXE_CH_STAT_INT_DONE_MASK & chStat)
      {
         /* Handle TX complete for high priority channel */
         status = dxeTXCompFrame(dxeCtxt,
                                 channelCb);
         bEnableISR = 1;
      }
      else if(WLANDXE_CH_STAT_INT_ED_MASK & chStat)
      {
         /* Handle TX complete for high priority channel */
         status = dxeTXCompFrame(dxeCtxt,
                                 channelCb);
         bEnableISR = 1;
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "dxeTXEventHandler TX HI status=%x", chStat);
      }

      if(WLANDXE_CH_STAT_MASKED_MASK & chStat)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH,
                  "dxeTXEventHandler TX HIGH Channel Masked Unmask it!!!!");
      }

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH,
               "TX HIGH STAT 0x%x RESRVD %d", chStat, channelCb->numRsvdDesc);
   }

   /* Test Low Priority Channel interrupt is enabled or not */
   channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI];
   if(intSrc & (1 << channelCb->assignedDMAChannel))
   {
      status = dxeChannelCleanInt(channelCb, &chStat);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeTXEventHandler INT Clean up fail");
         return;         
      }

      if(WLANDXE_CH_STAT_INT_ERR_MASK & chStat)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%11s : 0x%x Error Reported, Reload Driver",
                  channelType[channelCb->channelType], chStat);

         if (eWLAN_PAL_STATUS_SUCCESS !=
                         dxeErrHandler(channelCb, chStat))
         {
             dxeCtxt->driverReloadInProcessing = eWLAN_PAL_TRUE;
             wpalWlanReload(VOS_DXE_FAILURE);
             dxeStartSSRTimer(dxeCtxt);
         }
         bEnableISR = 1;
      }
      else if(WLANDXE_CH_STAT_INT_DONE_MASK & chStat)
      {
         /* Handle TX complete for low priority channel */
         status = dxeTXCompFrame(dxeCtxt,
                                 channelCb);
         bEnableISR = 1;
      }
      else if(WLANDXE_CH_STAT_INT_ED_MASK & chStat)
      {
         /* Handle TX complete for low priority channel */
         status = dxeTXCompFrame(dxeCtxt,
                                 channelCb);
         bEnableISR = 1;
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "dxeTXEventHandler TX LO status=%x", chStat);
      }

      if(WLANDXE_CH_STAT_MASKED_MASK & chStat)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_HIGH,
                  "dxeTXEventHandler TX Low Channel Masked Unmask it!!!!");
      }
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
               "TX LOW STAT 0x%x RESRVD %d", chStat, channelCb->numRsvdDesc);
   }

   if((bEnableISR || (dxeCtxt->txCompletedFrames)) &&
      (eWLAN_PAL_FALSE == dxeCtxt->txIntEnable))
   {
      dxeCtxt->txIntEnable =  eWLAN_PAL_TRUE; 
      wpalEnableInterrupt(DXE_INTERRUPT_TX_COMPLE);
      if(0 != dxeCtxt->txCompletedFrames)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                  "TX COMP INT Enabled, remain TX frame count on ring %d",
                  dxeCtxt->txCompletedFrames);
      }
   }

   if(eWLAN_PAL_TRUE == dxeCtxt->txIntEnable)
      DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_TXINT_STATE,
                       TRACE_WLANDXE_VAR_ENABLE));

   dxeEnvBlk.txCmpIntChanlSrc = 0;

   /*Kicking the DXE after the TX Complete interrupt was enabled - to avoid 
     the posibility of a race*/
   dxePsComplete(dxeCtxt, eWLAN_PAL_TRUE);

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}


/*==========================================================================
  @  Function Name 
      dxeTXCompleteProcessing

  @  Description 
      If DXE HW sends TX related interrupt, this event handler will be called
      Handle higher priority channel first
      Figureout why interrupt happen and call appropriate final even handler
      TX complete or error happen

  @  Parameters
      dxeCtxt      DXE context 

  @  Return
      PAL_STATUS_T
===========================================================================*/
void dxeTXCompleteProcessing
(
   WLANDXE_CtrlBlkType *dxeCtxt
)
{
   wpt_status                status     = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_ChannelCBType    *channelCb  = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);
  
   /* Test High Priority Channel is the INT source or not */
   channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI];

   /* Handle TX complete for high priority channel */
   status = dxeTXCompFrame(dxeCtxt, channelCb);

   /* Test Low Priority Channel interrupt is enabled or not */
   channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI];

   /* Handle TX complete for low priority channel */
   status = dxeTXCompFrame(dxeCtxt, channelCb);
  
   if((eWLAN_PAL_FALSE == dxeCtxt->txIntEnable) &&
      ((dxeCtxt->txCompletedFrames > 0) ||
       (WLANDXE_POWER_STATE_FULL == dxeCtxt->hostPowerState)))
   {
      dxeCtxt->txIntEnable =  eWLAN_PAL_TRUE; 
      wpalEnableInterrupt(DXE_INTERRUPT_TX_COMPLE);
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "%s %s : %d, %s : %d", __func__,
               channelType[dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].channelType],
               dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_HIGH_PRI].numRsvdDesc,
               channelType[dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].channelType],
               dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].numRsvdDesc);

      if((WLANDXE_POWER_STATE_FULL != dxeCtxt->hostPowerState) &&
         (eWLAN_PAL_FALSE == tempDxeCtrlBlk->smsmToggled))
      {
         /* After TX Comp processing, still remaining frame on the DXE TX ring
          * And when push frame, RING was not empty marked
          * Then when push frame, no SMSM toggle happen
          * To avoid permanent TX stall, SMSM toggle is needed at here
          * With this toggle, host should gaurantee SMSM state should be changed */
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
      }
   }
   
   /*Kicking the DXE after the TX Complete interrupt was enabled - to avoid 
     the posibility of a race*/
   dxePsComplete(dxeCtxt, eWLAN_PAL_FALSE);
   
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}

/*==========================================================================
  @  Function Name
      dxeTXReSyncDesc

  @  Description
      When STA comeout from IMPS, check DXE TX next transfer candidate descriptor
      And HW programmed descriptor.
      If any async happen between HW/SW TX stall will happen

  @  Parameters
      void    *msgPtr
               Message pointer to sync with TX thread

  @  Return
      NONE
===========================================================================*/
void dxeTXReSyncDesc
(
   wpt_msg                  *msgPtr
)
{
   wpt_msg                  *msgContent = (wpt_msg *)msgPtr;
   WLANDXE_CtrlBlkType      *pDxeCtrlBlk;
   wpt_uint32                nextDescReg;
   WLANDXE_ChannelCBType    *channelEntry;
   WLANDXE_DescCtrlBlkType  *validCtrlBlk;
   wpt_uint32                descLoop;
   wpt_uint32                channelLoop;

   if(NULL == msgContent)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXReSyncDesc Invalid Control Block");
      return;
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "dxeTXReSyncDesc Try to re-sync TX channel if any problem");
   pDxeCtrlBlk = (WLANDXE_CtrlBlkType *)(msgContent->pContext);

   for(channelLoop = WDTS_CHANNEL_TX_LOW_PRI; channelLoop < WDTS_CHANNEL_RX_LOW_PRI; channelLoop++)
   {
      channelEntry = &pDxeCtrlBlk->dxeChannel[channelLoop];
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
               "%11s : Try to detect TX descriptor async", channelType[channelEntry->channelType]);
      wpalReadRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                       &nextDescReg);
      /* Async detect without TX pending frame */
      if(channelEntry->tailCtrlBlk == channelEntry->headCtrlBlk)
      {
         if(nextDescReg != channelEntry->tailCtrlBlk->linkedDescPhyAddr)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                     "TX Async no Pending frame");

            dxeChannelMonitor("!!! TX Async no Pending frame !!!", channelEntry, NULL);
            dxeChannelRegisterDump(channelEntry, "!!! TX Async no Pending frame !!!", NULL);

            wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                              channelEntry->tailCtrlBlk->linkedDescPhyAddr);
         }
      }
      /* Async detect with some TX pending frames
       * next descriptor register should sync with first valid descriptor */
      else
      {
         validCtrlBlk = channelEntry->tailCtrlBlk;
         for(descLoop = 0; descLoop < channelEntry->numDesc; descLoop++)
         {
            if(validCtrlBlk->linkedDesc->descCtrl.ctrl & WLANDXE_DESC_CTRL_VALID)
            {
               if(nextDescReg != validCtrlBlk->linkedDescPhyAddr)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                           "TX Async");

                  dxeChannelMonitor("!!! TX Async !!!", channelEntry, NULL);
                  dxeChannelRegisterDump(channelEntry, "!!! TX Async !!!", NULL);

                  wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                    validCtrlBlk->linkedDescPhyAddr);
               }
               break;
            }
            validCtrlBlk = (WLANDXE_DescCtrlBlkType *)validCtrlBlk->nextCtrlBlk;
            if(validCtrlBlk == channelEntry->headCtrlBlk->nextCtrlBlk)
            {
               /* Finished to test till head control blcok, but could not find valid descriptor
                * from head to tail all descriptors are invalidated
                * host point of view head descriptor is next TX candidate
                * So, next descriptor control have to be programmed with head descriptor
                * check */
               if(nextDescReg != channelEntry->headCtrlBlk->linkedDescPhyAddr)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                           "TX Async with not completed transferred frames, next descriptor must be head");

                  dxeChannelMonitor("!!! TX Async !!!", channelEntry, NULL);
                  dxeChannelRegisterDump(channelEntry, "!!! TX Async !!!", NULL);

                  wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                    validCtrlBlk->linkedDescPhyAddr);
               }
               break;
            }
         }
      }
   }

   /* HW/SW descriptor resync is done.
    * Next if there are any valid descriptor in chain, Push to HW again */
   for(channelLoop = WDTS_CHANNEL_TX_LOW_PRI; channelLoop < WDTS_CHANNEL_RX_LOW_PRI; channelLoop++)
   {
      channelEntry = &pDxeCtrlBlk->dxeChannel[channelLoop];
      if(channelEntry->tailCtrlBlk == channelEntry->headCtrlBlk)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
                  "%11s : No TX Pending frame",
                  channelType[channelEntry->channelType]);
         /* No Pending frame, Do nothing */
      }
      else
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                  "%11s : TX Pending frame, process it",
                  channelType[channelEntry->channelType]);
         validCtrlBlk = channelEntry->tailCtrlBlk;
         for(descLoop = 0; descLoop < channelEntry->numDesc; descLoop++)
         {
            if(validCtrlBlk->linkedDesc->descCtrl.ctrl & WLANDXE_DESC_CTRL_VALID)
            {
               HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
                        "%11s : when exit IMPS found valid descriptor",
                        channelType[channelEntry->channelType]);

               /* Found valid descriptor, kick DXE */
               wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                                 channelEntry->extraConfig.chan_mask);
               break;
            }
            validCtrlBlk = (WLANDXE_DescCtrlBlkType *)validCtrlBlk->nextCtrlBlk;
            if(validCtrlBlk == channelEntry->headCtrlBlk->nextCtrlBlk)
            {
               /* Finished to test till head control blcok, but could not find valid descriptor
                * from head to tail all descriptors are invalidated */
               break;
            }
         }
      }
   }

   wpalMemoryFree(msgPtr);
   return;
}

/*==========================================================================
  @  Function Name
      dxeDebugTxDescReSync

  @  Description
       Check DXE Tx channel state and correct it in
       case Tx Data stall is detected by calling
       %dxeTXReSyncDesc. Also ensure that WCN SS
       is not power collapsed before calling
       %dxeTXReSyncDesc

  @  Parameters
      void    *msgPtr
               Message pointer to sync with TX thread

  @  Return
      NONE
===========================================================================*/
void dxeDebugTxDescReSync
(
   wpt_msg                  *msgPtr
)
{
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "%s: Check for DXE TX Async",__func__);
   /* Make wake up HW */
   dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
   dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);

   wpalSleep(10);

   dxeTXReSyncDesc(msgPtr);
}
/*==========================================================================
  @  Function Name 
      dxeTXISR

  @  Description 
      TX interrupt ISR
      Platform will call this function if INT is happen
      This function must be registered into platform interrupt module

  @  Parameters
      void    *hostCtxt
               DXE host driver control context,
               pre registerd during interrupt registration

  @  Return
      PAL_STATUS_T
===========================================================================*/
static void dxeTXISR
(
   void                    *hostCtxt
)
{
   WLANDXE_CtrlBlkType      *dxeCtxt = (WLANDXE_CtrlBlkType *)hostCtxt;
   wpt_status                status  = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                intSrc  = 0;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Return from here if the RIVA is in IMPS, to avoid register access */
   if(WLANDXE_POWER_STATE_DOWN == dxeCtxt->hostPowerState)
   {
      dxeCtxt->txIntEnable = eWLAN_PAL_FALSE;
      /* Disable interrupt at here,
         IMPS or IMPS Pending state should not access RIVA register */
      status = wpalDisableInterrupt(DXE_INTERRUPT_TX_COMPLE);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "dxeRXFrameReadyISR Disable RX ready interrupt fail");
         return;         
      }
      dxeCtxt->txIntDisabledByIMPS = eWLAN_PAL_TRUE;
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
         "%s Riva is in %d, return from here ", __func__, dxeCtxt->hostPowerState);
      return;
   }

   /* Disable TX Complete Interrupt at here */
   status = wpalDisableInterrupt(DXE_INTERRUPT_TX_COMPLE);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompISR Disable TX complete interrupt fail");
      return;         
   }
   dxeCtxt->txIntEnable = eWLAN_PAL_FALSE;

   wpalReadRegister(WLANDXE_INT_SRC_RAW_ADDRESS,
                                  &intSrc);
   /* intSrc which holds the INT_SRC_RAW_ADDRESS reg value
      While debugging crash dump convert to power of 2 for channel type */
   DXTRACE(dxeTrace(intSrc, TRACE_TXINT_STATE, TRACE_WLANDXE_VAR_DISABLE));

   if( dxeCtxt->ucTxMsgCnt )
   {
    HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
                 "Avoiding serializing TX Complete event");
    return;
   }

   dxeCtxt->ucTxMsgCnt = 1;

   /* Serialize TX complete interrupt upon TX thread */
   if(NULL == dxeCtxt->txIsrMsg)
   {
       HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "Invalid message");
       HDXE_ASSERT(0);
       return;
   }

   status = wpalPostTxMsg(WDI_GET_PAL_CTX(),
                          dxeCtxt->txIsrMsg);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "dxeTXCompISR interrupt serialize fail status=%d", status);
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}

/*==========================================================================
  @  Function Name
      dxeTraceInit

  @  Description
      Initialize the DXTRACE when enabled

  @  Parameters
      NONE

  @  Return
      NONE
===========================================================================*/
void dxeTraceInit(void)
{
   gdxeTraceData.head   = INVALID_VOS_TRACE_ADDR;
   gdxeTraceData.tail   = INVALID_VOS_TRACE_ADDR;
   gdxeTraceData.num    = 0;
   gdxeTraceData.enable = eWLAN_PAL_TRUE;
}

/*==========================================================================
  @  Function Name
      dxeTrace

  @  Description
       puts the messages in to ring-buffer

  @  Parameters
      v_U8_t   chan
               Rx/Tx path record
      v_U8_t   code
               Rx/Tx Event
      v_U32_t  data
               Actual message contents
  @  Return
      NONE
===========================================================================*/
void dxeTrace(v_U8_t chan, v_U8_t code, v_U32_t data)
{
    pdxeTraceRecord rec = NULL;
    unsigned long flags;

    if (!gdxeTraceData.enable)
    {
        return;
    }

    /* Aquire the lock and only one thread can access the buffer at a time */
    spin_lock_irqsave(&dtraceLock, flags);

    gdxeTraceData.num++;

    if (gdxeTraceData.num > MAX_DXE_TRACE_RECORDS)
    {
        gdxeTraceData.num = MAX_DXE_TRACE_RECORDS;
    }
    if (INVALID_VOS_TRACE_ADDR == gdxeTraceData.head)
    {
        /* first record */
        gdxeTraceData.head = 0;
        gdxeTraceData.tail = 0;
    }
    else
    {
        /* queue is not empty */
        v_U32_t tail = gdxeTraceData.tail + 1;
        if (MAX_DXE_TRACE_RECORDS == tail)
        {
            tail = 0;
        }
        if (gdxeTraceData.head == tail)
        {
            /* full */
            if (MAX_DXE_TRACE_RECORDS == ++gdxeTraceData.head)
            {
                gdxeTraceData.head = 0;
            }
        }
        gdxeTraceData.tail = tail;
    }

    rec = &gdxeTraceTbl[gdxeTraceData.tail];
    rec->code = code;
    rec->data = data;
    rec->time = vos_timer_get_system_time();
    rec->chan = chan;

    spin_unlock_irqrestore(&dtraceLock, flags);
}

/*-------------------------------------------------------------------------
 *  Global Function
 *-------------------------------------------------------------------------*/
/*==========================================================================
  @  Function Name 
      WLANDXE_Open

  @  Description 
      Open host DXE driver, allocate DXE resources
      Allocate, DXE local control block, DXE descriptor pool, DXE descriptor control block pool

  @  Parameters
      pVoid      pAdapter : Driver global control block pointer

  @  Return
      pVoid DXE local module control block pointer
===========================================================================*/
void *WLANDXE_Open
(
   void
)
{
   wpt_status              status = eWLAN_PAL_STATUS_SUCCESS;
   unsigned int            idx;
   WLANDXE_ChannelCBType  *currentChannel = NULL;
   int                     smsmInitState;
   wpt_uint8               chanMask = WDTS_TRANSPORT_CHANNELS_MASK;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   if (wpalIsFwLoggingEnabled())
   {
      chanMask |= WDTS_RX_LOG_CHANNEL_MASK;
   }

   if (wpalIsFwEvLoggingEnabled())
   {
      chanMask |= WDTS_RX_FW_LOG_CHANNEL_MASK;
   }
   dxeSetEnabledChannels(chanMask);

   /* This is temporary allocation */
   tempDxeCtrlBlk = (WLANDXE_CtrlBlkType *)wpalMemoryAllocate(sizeof(WLANDXE_CtrlBlkType));
   if(NULL == tempDxeCtrlBlk)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Open Control Block Alloc Fail");
      return NULL;  
   }
   wpalMemoryZero(tempDxeCtrlBlk, sizeof(WLANDXE_CtrlBlkType));

   dxeCommonDefaultConfig(tempDxeCtrlBlk);

   foreach_valid_channel(idx)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "WLANDXE_Open Channel %s Open Start", channelType[idx]);
      currentChannel = &tempDxeCtrlBlk->dxeChannel[idx];
      currentChannel->channelType = idx;

      /* Config individual channels from channel default setup table */
      status = dxeChannelDefaultConfig(tempDxeCtrlBlk,
                                       currentChannel);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Open Channel Basic Configuration Fail for channel %d", idx);
         WLANDXE_Close(tempDxeCtrlBlk);
         return NULL;         
      }

      /* Allocate DXE Control Block will be used by host DXE driver */
      status = dxeCtrlBlkAlloc(tempDxeCtrlBlk, currentChannel);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Open Alloc DXE Control Block Fail for channel %d", idx);

         WLANDXE_Close(tempDxeCtrlBlk);
         return NULL;         
      }
      status = wpalMutexInit(&currentChannel->dxeChannelLock); 
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
                  "WLANDXE_Open Lock Init Fail for channel %d", idx);
         WLANDXE_Close(tempDxeCtrlBlk);
         return NULL;
      }

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "WLANDXE_Open Channel %s Open Success", channelType[idx]);
   }

   /* Allocate and Init RX READY ISR Serialize Buffer */
   tempDxeCtrlBlk->rxIsrMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
   if(NULL == tempDxeCtrlBlk->rxIsrMsg)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Open Alloc RX ISR Fail");
      WLANDXE_Close(tempDxeCtrlBlk);
      return NULL;
   }
   wpalMemoryZero(tempDxeCtrlBlk->rxIsrMsg, sizeof(wpt_msg));
   tempDxeCtrlBlk->rxIsrMsg->callback = dxeRXEventHandler;
   tempDxeCtrlBlk->rxIsrMsg->pContext = (void *)tempDxeCtrlBlk;

   /* Allocate and Init TX COMP ISR Serialize Buffer */
   tempDxeCtrlBlk->txIsrMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
   if(NULL == tempDxeCtrlBlk->txIsrMsg)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Open Alloc TX ISR Fail");
      WLANDXE_Close(tempDxeCtrlBlk);
      return NULL;
   }
   wpalMemoryZero(tempDxeCtrlBlk->txIsrMsg, sizeof(wpt_msg));
   tempDxeCtrlBlk->txIsrMsg->callback = dxeTXEventHandler;
   tempDxeCtrlBlk->txIsrMsg->pContext = (void *)tempDxeCtrlBlk;

   /* Allocate and Init RX Packet Available Serialize Message Buffer */
   tempDxeCtrlBlk->rxPktAvailMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
   if(NULL == tempDxeCtrlBlk->rxPktAvailMsg)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Open Alloc RX Packet Available Message Fail");
      WLANDXE_Close(tempDxeCtrlBlk);
      return NULL;
   }
   wpalMemoryZero(tempDxeCtrlBlk->rxPktAvailMsg, sizeof(wpt_msg));
   tempDxeCtrlBlk->rxPktAvailMsg->callback = dxeRXPacketAvailableEventHandler;
   tempDxeCtrlBlk->rxPktAvailMsg->pContext = (void *)tempDxeCtrlBlk;
   
   tempDxeCtrlBlk->freeRXPacket = NULL;
   tempDxeCtrlBlk->dxeCookie    = WLANDXE_CTXT_COOKIE;
   tempDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_FALSE;
   tempDxeCtrlBlk->txIntDisabledByIMPS = eWLAN_PAL_FALSE;
   tempDxeCtrlBlk->driverReloadInProcessing = eWLAN_PAL_FALSE;
   tempDxeCtrlBlk->smsmToggled              = eWLAN_PAL_FALSE;
   tempDxeCtrlBlk->smsmRingsEmptyHistogram  = 0;
   tempDxeCtrlBlk->smsmDxeHistogram         = 0;

   /* Initialize SMSM state
    * Init State is
    *    Clear TX Enable
    *    RING EMPTY STATE */
   smsmInitState = wpalNotifySmsm(WPAL_SMSM_WLAN_TX_ENABLE |
                                  WPAL_SMSM_WLAN_TX_RINGS_EMPTY,
                                  WPAL_SMSM_WLAN_TX_RINGS_EMPTY);
   if(0 != smsmInitState)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "SMSM Channel init fail %d", smsmInitState);
      foreach_valid_channel(idx)
      {
         dxeChannelClose(tempDxeCtrlBlk, &tempDxeCtrlBlk->dxeChannel[idx]);
      }
      wpalMemoryFree(tempDxeCtrlBlk->rxIsrMsg);
      wpalMemoryFree(tempDxeCtrlBlk->txIsrMsg);
      wpalMemoryFree(tempDxeCtrlBlk);
      return NULL;
   }

#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
   wpalTimerInit(&tempDxeCtrlBlk->rxResourceAvailableTimer,
                 dxeRXResourceAvailableTimerExpHandler,
                 tempDxeCtrlBlk);
#endif

   wpalTimerInit(&tempDxeCtrlBlk->dxeSSRTimer,
                 dxeSSRTimerExpHandler, tempDxeCtrlBlk);

   spin_lock_init(&dtraceLock);

#ifdef DXE_TRACE
   DXTRACE(dxeTraceInit());
#endif

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
            "WLANDXE_Open Success");
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return (void *)tempDxeCtrlBlk;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_ClientRegistration

  @  Description 
      Make callback functions registration into DXE driver from DXE driver client

  @  Parameters
      pVoid                       pDXEContext : DXE module control block
      WDTS_ClientCallbacks        WDTSCb : Callbacks to WDTS to indicate various events
      void                       *userContext : DXE Cliennt control block

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_ClientRegistration
(
   void                       *pDXEContext,
   WDTS_ClientCallbacks       WDTSCb,
   void                       *userContext
)
{
   wpt_status                 status  = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_CtrlBlkType       *dxeCtxt;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_ClientRegistration Invalid DXE CB");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   if(NULL == userContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_ClientRegistration Invalid userContext");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   dxeCtxt = (WLANDXE_CtrlBlkType *)pDXEContext;

   /* Assign */
   dxeCtxt->rxReadyCB     = WDTSCb.rxFrameReadyCB;
   dxeCtxt->txCompCB      = WDTSCb.txCompleteCB;
   dxeCtxt->lowResourceCB = WDTSCb.lowResourceCB;
   dxeCtxt->receiveMbMsgCB = WDTSCb.receiveMbMsgCB;
   dxeCtxt->receiveLogCompleteCB = WDTSCb.receiveLogCompleteCB;
   dxeCtxt->clientCtxt    = userContext;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_Start

  @  Description 
      Start Host DXE driver
      Initialize DXE channels and start channel

  @  Parameters
      pVoid                       pDXEContext : DXE module control block

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_Start
(
   void  *pDXEContext
)
{
   wpt_status                 status  = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                 idx;
   WLANDXE_CtrlBlkType       *dxeCtxt = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start Invalid DXE CB");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }
   dxeCtxt = (WLANDXE_CtrlBlkType *)pDXEContext;

   /* WLANDXE_Start called means DXE engine already initiates
    * And DXE HW is reset and init finished
    * But here to make sure HW is initialized, reset again */
   dxeEngineCoreStart(dxeCtxt);

   /* Individual Channel Start */
   foreach_valid_channel(idx)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "WLANDXE_Start Channel %s Start", channelType[idx]);

      /* Allocate DXE descriptor will be shared by Host driver and DXE engine */
      /* Make connection between DXE descriptor and DXE control block */
      status = dxeDescAllocAndLink(tempDxeCtrlBlk, &dxeCtxt->dxeChannel[idx]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Start Alloc DXE Descriptor Fail for channel %d", idx);
         return status;         
      }

      /* Program each channel register with configuration arguments */
      status = dxeChannelInitProgram(dxeCtxt,
                                     &dxeCtxt->dxeChannel[idx]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Start %d Program DMA channel Fail", idx);
         return status;         
      }

      /* ??? Trigger to start DMA channel
       * This must be seperated from ??? */
      status = dxeChannelStart(dxeCtxt,
                               &dxeCtxt->dxeChannel[idx]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Start %d Channel Start Fail", idx);
         return status;         
      }
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "WLANDXE_Start Channel %s Start Success", channelType[idx]);
   }

   /* Register ISR to OS */
   /* Register TX complete interrupt into platform */
   status = wpalRegisterInterrupt(DXE_INTERRUPT_TX_COMPLE,
                                       dxeTXISR,
                                       dxeCtxt);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start TX comp interrupt registration Fail");
      return status;         
   }

   /* Register RX ready interrupt into platform */
   status = wpalRegisterInterrupt(DXE_INTERRUPT_RX_READY,
                                       dxeRXISR,
                                       dxeCtxt);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start RX Ready interrupt registration Fail");
      return status;         
   }

   /* Enable system level ISR */
   /* Enable RX ready Interrupt at here */
   status = wpalEnableInterrupt(DXE_INTERRUPT_RX_READY);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeTXCompleteEventHandler Enable TX complete interrupt fail");
      return status;         
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_TXFrame

  @  Description 
      Trigger frame transmit from host to RIVA

  @  Parameters
      pVoid            pDXEContext : DXE Control Block
      wpt_packet       pPacket : transmit packet structure
      WDTS_ChannelType channel : TX channel

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_TxFrame
(
   void                *pDXEContext,
   wpt_packet          *pPacket,
   WDTS_ChannelType     channel
)
{
   wpt_status                 status         = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_ChannelCBType     *currentChannel = NULL;
   WLANDXE_CtrlBlkType       *dxeCtxt        = NULL;
   unsigned int              *lowThreshold   = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start Invalid DXE CB");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   if(NULL == pPacket)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start Invalid pPacket");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   if(WDTS_CHANNEL_MAX <= channel)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Start Invalid channel");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   dxeCtxt = (WLANDXE_CtrlBlkType *)pDXEContext;

   currentChannel = &dxeCtxt->dxeChannel[channel];
   

   status = wpalMutexAcquire(&currentChannel->dxeChannelLock);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_TxFrame Mutex Acquire fail");
      return status;
   }

   lowThreshold = currentChannel->channelType == WDTS_CHANNEL_TX_LOW_PRI?
      &(dxeCtxt->txCompInt.txLowResourceThreshold_LoPriCh):
      &(dxeCtxt->txCompInt.txLowResourceThreshold_HiPriCh);

   /* Decide have to activate TX complete event or not */
   switch(dxeCtxt->txCompInt.txIntEnable)
   {
      /* TX complete interrupt will be activated when low DXE resource */
      case WLANDXE_TX_COMP_INT_LR_THRESHOLD:
         if((currentChannel->numFreeDesc <= *lowThreshold) &&
            (eWLAN_PAL_FALSE == dxeCtxt->txIntEnable))
         {
            dxeCtxt->txIntEnable = eWLAN_PAL_TRUE;
            dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                                   channel,
                                   eWLAN_PAL_FALSE);
         }
         break;

      /* TX complete interrupt will be activated n number of frames transferred */
      case WLANDXE_TX_COMP_INT_PER_K_FRAMES:
         if(channel == WDTS_CHANNEL_TX_LOW_PRI)
         {
            currentChannel->numFrameBeforeInt++;
         }
         break;

      /* TX complete interrupt will be activated periodically */
      case WLANDXE_TX_COMP_INT_TIMER:
         break;
   }

   dxeCtxt->txCompletedFrames++;

   /* Update DXE descriptor, this is frame based
    * if a frame consist of N fragments, N Descriptor will be programed */
   status = dxeTXPushFrame(currentChannel, pPacket);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_TxFrame TX Push Frame fail");
      status = wpalMutexRelease(&currentChannel->dxeChannelLock);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_TxFrame Mutex Release fail");
      }
      return status;
   }

   /* If specific channel hit low resource condition, send notification to upper layer */
   if(currentChannel->numFreeDesc <= *lowThreshold)
   {
      dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                             channel,
                             eWLAN_PAL_FALSE);
      currentChannel->hitLowResource = eWLAN_PAL_TRUE;

      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_WARN,
               "%11s : Low Resource currentChannel->numRsvdDesc %d",
               channelType[currentChannel->channelType],
               currentChannel->numRsvdDesc);
      if (WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN == dxeCtxt->rivaPowerState)
      {
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
      }
   }
   status = wpalMutexRelease(&currentChannel->dxeChannelLock);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_TxFrame Mutex Release fail");
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_CompleteTX

  @  Description 
      Informs DXE that the current series of Tx packets is complete

  @  Parameters
      pContext            pDXEContext : DXE Control Block
      ucTxResReq          TX resource number required by TL/WDI

  @  Return
      wpt_status
===========================================================================*/
wpt_status
WLANDXE_CompleteTX
(
  void* pContext,
  wpt_uint32 ucTxResReq
)
{
  wpt_status                status  = eWLAN_PAL_STATUS_SUCCESS;
  WLANDXE_CtrlBlkType      *dxeCtxt = (WLANDXE_CtrlBlkType *)(pContext);
  WLANDXE_ChannelCBType    *channelCb  = NULL;
  wpt_boolean               inLowRes;

  /* Sanity Check */
  if( NULL == pContext )
  {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_CompleteTX invalid param");
      return eWLAN_PAL_STATUS_E_INVAL;
  }

  channelCb = &dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI];
  inLowRes  = channelCb->hitLowResource;

  if(WLANDXE_TX_LOW_RES_THRESHOLD < ucTxResReq)
  {
    /* Raise threshold temporarily if necessary */
    dxeCtxt->txCompInt.txLowResourceThreshold_LoPriCh = ucTxResReq;

    if(eWLAN_PAL_FALSE == inLowRes)
    {
      /* Put the channel to low resource condition */
      dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                             WDTS_CHANNEL_TX_LOW_PRI,
                             eWLAN_PAL_FALSE);
      inLowRes = channelCb->hitLowResource = eWLAN_PAL_TRUE;
    }
  }

  /*Try to reclaim resources*/
  dxeTXCompleteProcessing(dxeCtxt);

  /* In previous WLANTL_GetFrames call, TL didn't fetch a packet 
     because its fragment size is larger than DXE free resource. */
  if(0 < ucTxResReq)
  {
    /* DXE successfully claimed enough free DXE resouces for next fetch. */
    if(WLANDXE_GetFreeTxDataResNumber(dxeCtxt) >= ucTxResReq)
    {
      /* DXE has not been in low resource condition. DXE forces to kick off
         TX tranmit */
      if((eWLAN_PAL_FALSE == inLowRes) && 
         (eWLAN_PAL_FALSE == channelCb->hitLowResource))
      {
        dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                               WDTS_CHANNEL_TX_LOW_PRI,
                               eWLAN_PAL_FALSE);
        dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                               WDTS_CHANNEL_TX_LOW_PRI,
                               eWLAN_PAL_TRUE);
        channelCb->hitLowResource = eWLAN_PAL_FALSE;
      }
    }
    else
    {
      /* DXE doesn't have enough free DXE resources. Put the channel
         to low resource condition. */
      if(eWLAN_PAL_FALSE == channelCb->hitLowResource)
      {
        /* Put the channel to low resource condition */
        dxeCtxt->lowResourceCB(dxeCtxt->clientCtxt,
                             WDTS_CHANNEL_TX_LOW_PRI,
                             eWLAN_PAL_FALSE);
        channelCb->hitLowResource = eWLAN_PAL_TRUE;
      }
    }
  }
 
  return status; 
}

/*==========================================================================
  @  Function Name 
      WLANDXE_Stop

  @  Description 
      Stop DXE channels and DXE engine operations
      Disable all channel interrupt
      Stop all channel operation

  @  Parameters
      pVoid            pDXEContext : DXE Control Block

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_Stop
(
   void *pDXEContext
)
{
   wpt_status                 status = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                 idx;
   WLANDXE_CtrlBlkType       *dxeCtxt = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Stop Invalid DXE CB");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   dxeCtxt = (WLANDXE_CtrlBlkType *)pDXEContext;
   foreach_valid_channel(idx)
   {
      status = dxeChannelStop(dxeCtxt, &dxeCtxt->dxeChannel[idx]);
      if(eWLAN_PAL_STATUS_SUCCESS != status)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_Stop Channel %d Stop Fail", idx);
      }
   }

   /* During Stop unregister interrupt */
   wpalUnRegisterInterrupt(DXE_INTERRUPT_TX_COMPLE);
   wpalUnRegisterInterrupt(DXE_INTERRUPT_RX_READY);

#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
   if(VOS_TIMER_STATE_STOPPED !=
      wpalTimerGetCurStatus(&dxeCtxt->rxResourceAvailableTimer))
   {
      wpalTimerStop(&dxeCtxt->rxResourceAvailableTimer);
   }
#endif

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_Close

  @  Description 
      Close DXE channels
      Free DXE related resources
      DXE descriptor free
      Descriptor control block free
      Pre allocated RX buffer free

  @  Parameters
      pVoid            pDXEContext : DXE Control Block

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_Close
(
   void *pDXEContext
)
{
   wpt_status               status = eWLAN_PAL_STATUS_SUCCESS;
   wpt_uint32                 idx;
   WLANDXE_CtrlBlkType       *dxeCtxt = NULL;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Sanity */
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "WLANDXE_Stop Invalid DXE CB");
      return eWLAN_PAL_STATUS_E_INVAL;   
   }

   dxeCtxt = (WLANDXE_CtrlBlkType *)pDXEContext;
#ifdef WLAN_DXE_LOW_RESOURCE_TIMER
   wpalTimerDelete(&dxeCtxt->rxResourceAvailableTimer);
#endif
   wpalTimerDelete(&dxeCtxt->dxeSSRTimer);
   foreach_valid_channel(idx)
   {
      wpalMutexDelete(&dxeCtxt->dxeChannel[idx].dxeChannelLock);
      dxeChannelClose(dxeCtxt, &dxeCtxt->dxeChannel[idx]);
   }

   if(NULL != dxeCtxt->rxIsrMsg)
   {
      wpalMemoryFree(dxeCtxt->rxIsrMsg);
   }
   if(NULL != dxeCtxt->txIsrMsg)
   {
      wpalMemoryFree(dxeCtxt->txIsrMsg);
   }
   if(NULL != dxeCtxt->rxPktAvailMsg)
   {
      wpalMemoryFree(dxeCtxt->rxPktAvailMsg);
   }

   wpalMemoryFree(pDXEContext);

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_TriggerTX

  @  Description 
      TBD

  @  Parameters
      pVoid            pDXEContext : DXE Control Block

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_TriggerTX
(
   void *pDXEContext
)
{
   wpt_status               status = eWLAN_PAL_STATUS_SUCCESS;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* TBD */

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return status;
}

/*==========================================================================
  @  Function Name 
      dxeTxThreadSetPowerStateEventHandler

  @  Description 
      If WDI sends set power state req, this event handler will be called in Tx
      thread context

  @  Parameters
         void               *msgPtr
                             Event MSG

  @  Return
      None
===========================================================================*/
void dxeTxThreadSetPowerStateEventHandler
(
    wpt_msg               *msgPtr
)
{
   wpt_msg                  *msgContent = (wpt_msg *)msgPtr;
   WLANDXE_CtrlBlkType      *dxeCtxt;
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_PowerStateType    reqPowerState;
   wpt_int8                  i;
   WLANDXE_ChannelCBType     *channelEntry;
   wpt_log_data_stall_channel_type channelLog;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   dxeCtxt = (WLANDXE_CtrlBlkType *)(msgContent->pContext);
   reqPowerState = (WLANDXE_PowerStateType)msgContent->val;
   dxeCtxt->setPowerStateCb = (WLANDXE_SetPowerStateCbType)msgContent->ptr;

   switch(reqPowerState)
   {
      case WLANDXE_POWER_STATE_BMPS:
         if(WLANDXE_RIVA_POWER_STATE_ACTIVE == dxeCtxt->rivaPowerState)
         {
            //don't block MC waiting for num_rsvd to become 0 since it may take a while
            //based on amount of TX and RX activity - during this time any received 
            // management frames will remain un-processed consuming RX buffers
            dxeCtxt->rivaPowerState = WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN;
            dxeCtxt->hostPowerState = reqPowerState;
         }
         else
         {
            status = eWLAN_PAL_STATUS_E_INVAL;
         }
         break;
      case WLANDXE_POWER_STATE_IMPS:
         if(WLANDXE_RIVA_POWER_STATE_ACTIVE == dxeCtxt->rivaPowerState)
         {

            for(i = WDTS_CHANNEL_TX_LOW_PRI; i < WDTS_CHANNEL_RX_LOW_PRI; i++)
            {
               channelEntry = &dxeCtxt->dxeChannel[i];
               if(channelEntry->tailCtrlBlk != channelEntry->headCtrlBlk)
               {
                  status = eWLAN_PAL_STATUS_E_FAILURE;
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
                           "%11s : %s :TX Pending frame",
                           channelType[channelEntry->channelType], __func__);

                  dxeChannelMonitor("DXE_IMP_ERR", channelEntry, &channelLog);
                  dxeDescriptorDump(channelEntry,
                                    channelEntry->headCtrlBlk->linkedDesc, 0);
                  dxeChannelRegisterDump(channelEntry, "DXE_IMPS_ERR",
                                         &channelLog);
                  dxeChannelAllDescDump(channelEntry,
                                        channelEntry->channelType,
                                        &channelLog);
               }
            }

            if (eWLAN_PAL_STATUS_SUCCESS == status)
            {
               dxeCtxt->rivaPowerState = WLANDXE_RIVA_POWER_STATE_IMPS_UNKNOWN;
               dxeCtxt->hostPowerState = WLANDXE_POWER_STATE_IMPS;
            }
         }
         else
         {
            status = eWLAN_PAL_STATUS_E_INVAL;
         }
         break;
      case WLANDXE_POWER_STATE_FULL:
         if(WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN == dxeCtxt->rivaPowerState)
         {
            dxeCtxt->rivaPowerState = WLANDXE_RIVA_POWER_STATE_ACTIVE;
         }
         dxeCtxt->hostPowerState = reqPowerState;
         dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         break;
      case WLANDXE_POWER_STATE_DOWN:
         WLANDXE_Stop((void *)dxeCtxt);         
         break;
      default:
         //assert
         break;
   }

   DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_POWER_STATE, dxeCtxt->hostPowerState));

   if(WLANDXE_POWER_STATE_BMPS_PENDING != dxeCtxt->hostPowerState)
   {
      dxeCtxt->setPowerStateCb(status, 
                               dxeCtxt->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].descBottomLocPhyAddr);
   }
   else
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
            "%s State of DXE is WLANDXE_POWER_STATE_BMPS_PENDING, so cannot proceed", __func__);
   }
   /* Free MSG buffer */
   wpalMemoryFree(msgPtr);
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
   return;
}


/*==========================================================================
  @  Function Name 
      dxeRxThreadSetPowerStateEventHandler

  @  Description 
      If WDI sends set power state req, this event handler will be called in Rx
      thread context

  @  Parameters
         void               *msgPtr
                             Event MSG

  @  Return
      None
===========================================================================*/
void dxeRxThreadSetPowerStateEventHandler
(
    wpt_msg               *msgPtr
)
{
   wpt_status               status = eWLAN_PAL_STATUS_SUCCESS;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   /* Now serialise the message through Tx thread also to make sure
    * no register access when RIVA is in powersave */
   /*Use the same message pointer just change the call back function */
   msgPtr->callback = dxeTxThreadSetPowerStateEventHandler;
   status = wpalPostTxMsg(WDI_GET_PAL_CTX(),
                       msgPtr);
   if ( eWLAN_PAL_STATUS_SUCCESS != status )
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "Tx thread Set power state req serialize fail status=%d",
               status);
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);
}

/*==========================================================================
  @  Function Name 
      WLANDXE_SetPowerState

  @  Description 
      From Client let DXE knows what is the WLAN HW(RIVA) power state

  @  Parameters
      pVoid                    pDXEContext : DXE Control Block
      WLANDXE_PowerStateType   powerState

  @  Return
      wpt_status
===========================================================================*/
wpt_status WLANDXE_SetPowerState
(
   void                    *pDXEContext,
   WDTS_PowerStateType      powerState,
   WDTS_SetPSCbType         cBack
)
{
   wpt_status               status = eWLAN_PAL_STATUS_SUCCESS;
   WLANDXE_CtrlBlkType     *pDxeCtrlBlk;
   WLANDXE_PowerStateType   hostPowerState;
   wpt_msg                 *rxCompMsg;
   wpt_msg                 *txDescReSyncMsg;
   int                      state;

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);
   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "NULL pDXEContext passed by caller");
      return eWLAN_PAL_STATUS_E_FAILURE;
   }
   pDxeCtrlBlk = (WLANDXE_CtrlBlkType *)pDXEContext;

   switch(powerState)
   {
      case WDTS_POWER_STATE_FULL:
         dxeEnvBlk.dxe_prev_ps = pDxeCtrlBlk->hostPowerState;
         if(WLANDXE_POWER_STATE_IMPS == pDxeCtrlBlk->hostPowerState)
         {
            txDescReSyncMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
            if(NULL == txDescReSyncMsg)
            {
               HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                        "WLANDXE_SetPowerState, TX Resync MSG MEM alloc Fail");
            }
            else
            {
               txDescReSyncMsg->callback = dxeTXReSyncDesc;
               txDescReSyncMsg->pContext = pDxeCtrlBlk;
               status = wpalPostTxMsg(WDI_GET_PAL_CTX(),
                                      txDescReSyncMsg);
               if(eWLAN_PAL_STATUS_SUCCESS != status)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                           "WLANDXE_SetPowerState, Post TX re-sync MSG fail");
               }
            }
         }
         hostPowerState = WLANDXE_POWER_STATE_FULL;
         break;
      case WDTS_POWER_STATE_BMPS:
         pDxeCtrlBlk->hostPowerState = WLANDXE_POWER_STATE_BMPS;
         hostPowerState = WLANDXE_POWER_STATE_BMPS;
         break;
      case WDTS_POWER_STATE_IMPS:
         hostPowerState = WLANDXE_POWER_STATE_IMPS;
         break;
      case WDTS_POWER_STATE_DOWN:
         pDxeCtrlBlk->hostPowerState = WLANDXE_POWER_STATE_DOWN;
         hostPowerState = WLANDXE_POWER_STATE_DOWN;
         break;
      default:
         hostPowerState = WLANDXE_POWER_STATE_MAX;
   }

   // A callback i.e. ACK back is needed only when we want to enable BMPS
   // and the data/management path is active because we want to ensure
   // DXE registers are not accessed when RIVA may be power-collapsed. So
   // we need a callback in enter_bmps_req (the request to RIVA is sent
   // only after ACK back from TX thread). A callback is not needed in
   // finish_scan_req during BMPS since data-path is resumed only in 
   // finish_scan_rsp and no management frames are sent in between. No 
   // callback is needed when going from BMPS enabled to BMPS suspended/
   // disabled when it is known that RIVA is awake and cannot enter power
   // collapse autonomously so no callback is needed in exit_bmps_rsp or
   // init_scan_rsp
   if ( cBack )
   {
      //serialize through Rx thread
      rxCompMsg          = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
      if(NULL == rxCompMsg)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_SetPowerState, MSG MEM alloc Fail");
         return eWLAN_PAL_STATUS_E_RESOURCES;
      }

      /* Event type, where it must be defined???? */
      /* THIS MUST BE CLEARED ASAP
      txCompMsg->type     = TX_COMPLETE; */
      rxCompMsg->callback = dxeRxThreadSetPowerStateEventHandler;
      rxCompMsg->pContext = pDxeCtrlBlk;
      rxCompMsg->val      = hostPowerState;
      rxCompMsg->ptr      = cBack;
      status = wpalPostRxMsg(WDI_GET_PAL_CTX(),
                          rxCompMsg);
      if ( eWLAN_PAL_STATUS_SUCCESS != status )
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "Rx thread Set power state req serialize fail status=%d",
                  status);
      }
   }
   else
   {
      if ( WLANDXE_POWER_STATE_FULL == hostPowerState )
      {
         if( WLANDXE_POWER_STATE_BMPS == pDxeCtrlBlk->hostPowerState )
         {
            dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
         }
         else if( WLANDXE_POWER_STATE_IMPS == pDxeCtrlBlk->hostPowerState )
         {
            /* Requested Full power from exit IMPS, reenable the interrupts*/
            if(eWLAN_PAL_TRUE == pDxeCtrlBlk->rxIntDisabledByIMPS)
            {
               pDxeCtrlBlk->rxIntDisabledByIMPS = eWLAN_PAL_FALSE;
               /* Enable RX interrupt at here, if new PS is not IMPS */
               status = wpalEnableInterrupt(DXE_INTERRUPT_RX_READY);
               if(eWLAN_PAL_STATUS_SUCCESS != status)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                           "%s Enable RX ready interrupt fail", __func__);
                  return status;
               }
            }
            if(eWLAN_PAL_TRUE == pDxeCtrlBlk->txIntDisabledByIMPS)
            {
               pDxeCtrlBlk->txIntDisabledByIMPS = eWLAN_PAL_FALSE;
               pDxeCtrlBlk->txIntEnable =  eWLAN_PAL_TRUE;
               /* Enable RX interrupt at here, if new PS is not IMPS */
               status = wpalEnableInterrupt(DXE_INTERRUPT_TX_COMPLE);
               if(eWLAN_PAL_STATUS_SUCCESS != status)
               {
                  HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                           "%s Enable TX comp interrupt fail", __func__);
                  return status;
               }
            }
         }
         pDxeCtrlBlk->hostPowerState = hostPowerState;
         pDxeCtrlBlk->rivaPowerState = WLANDXE_RIVA_POWER_STATE_ACTIVE;
      }
      else if ( hostPowerState == WLANDXE_POWER_STATE_BMPS )
      {
         pDxeCtrlBlk->hostPowerState = hostPowerState;
         pDxeCtrlBlk->rivaPowerState = WLANDXE_RIVA_POWER_STATE_BMPS_UNKNOWN;
      }
      else if ( hostPowerState == WLANDXE_POWER_STATE_IMPS )
      {
         pDxeCtrlBlk->hostPowerState = WLANDXE_POWER_STATE_IMPS;
      }
      else
      {
         HDXE_ASSERT(0);
      }
      DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_POWER_STATE,
                                                pDxeCtrlBlk->hostPowerState));
   }

   if (WDTS_POWER_STATE_FULL == powerState &&
       WLANDXE_POWER_STATE_FULL == pDxeCtrlBlk->hostPowerState) {
      state = wpal_get_int_state(DXE_INTERRUPT_RX_READY);
      if (0 == state && eWLAN_PAL_TRUE == pDxeCtrlBlk->rxIntDisabledByIMPS) {
          dxeEnvBlk.rx_imps_set_fp = 1;
          WARN_ON(1);
      }
   }

   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Exit", __func__);

   return status;
}

/*==========================================================================
  @  Function Name 
      WLANDXE_GetFreeTxDataResNumber

  @  Description 
      Returns free descriptor numbers for TX data channel (TX high priority)

  @  Parameters
      pVoid            pDXEContext : DXE Control Block

  @  Return
      wpt_uint32      Free descriptor number of TX high pri ch
===========================================================================*/
wpt_uint32 WLANDXE_GetFreeTxDataResNumber
(
   void *pDXEContext
)
{
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO_LOW,
            "%s Enter", __func__);

   if(NULL == pDXEContext)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "NULL parameter passed by caller");
      return (0);
   }

   return ((WLANDXE_CtrlBlkType *)pDXEContext)->dxeChannel[WDTS_CHANNEL_TX_LOW_PRI].numFreeDesc;
}

/*==========================================================================
  @  Function Name
    WLANDXE_ChannelDebug

  @  Description
    Display DXE Channel debugging information
    User may request to display DXE channel snapshot
    Or if host driver detects any abnormal stcuk may display

  @  Parameters
    displaySnapshot : Display DXE snapshot option
    debugFlags      : Enable stall detect features
                      defined by WPAL_DeviceDebugFlags
                      These features may effect
                      data performance.

  @  Return
    NONE

===========================================================================*/
void WLANDXE_ChannelDebug
(
   wpt_boolean displaySnapshot,
   wpt_uint8   debugFlags
)
{
   wpt_msg                  *channelDebugMsg;
   wpt_msg                  *txDescReSyncMsg ;
   wpt_uint32                regValue, regValueLocal = 0;
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;

   /* Debug Type 1, Display current snapshot */
   if(displaySnapshot)
   {
      /* Whatever RIVA power condition try to wakeup RIVA through SMSM
       * This will not simply wakeup RIVA
       * Just incase TX not wanted stuck, Trigger TX again */
      dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
      dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
      /* Get free BD count */
      wpalSleep(10);
      wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU, &regValue);
#ifdef WCN_PRONTO
      wpalReadRegister(WLANDXE_BMU_AVAILABLE_BD_PDU_LOCAL, &regValueLocal);
#endif
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
               "===== DXE Dump Start HPS %d, FWS %d, TX PFC %d, ABD %d, ABD LOCAL %d =====",
               tempDxeCtrlBlk->hostPowerState, tempDxeCtrlBlk->rivaPowerState,
               tempDxeCtrlBlk->txCompletedFrames, regValue, regValueLocal);

      wpalPacketStallUpdateInfo((wpt_uint32 *)&tempDxeCtrlBlk->rivaPowerState,
                                &regValue,
                                NULL,
                                0);

      channelDebugMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
      if(NULL == channelDebugMsg)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "WLANDXE_ChannelDebug, MSG MEM alloc Fail");
         return ;
      }

      channelDebugMsg->callback = dxeRxThreadChannelDebugHandler;
      status = wpalPostRxMsg(WDI_GET_PAL_CTX(), channelDebugMsg);
      if ( eWLAN_PAL_STATUS_SUCCESS != status )
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "Tx thread Set power state req serialize fail status=%d",
                  status);
      }
   }

   if(debugFlags & WPAL_DEBUG_TX_DESC_RESYNC)
   {
      txDescReSyncMsg = (wpt_msg *)wpalMemoryAllocate(sizeof(wpt_msg));
      if(NULL == txDescReSyncMsg)
      {
         HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                  "%s: Resync MSG MEM alloc Fail",__func__);
      }
      else
      {
         txDescReSyncMsg->callback = dxeDebugTxDescReSync;
         txDescReSyncMsg->pContext = tempDxeCtrlBlk;
         status = wpalPostTxMsg(WDI_GET_PAL_CTX(),
                                txDescReSyncMsg);
         if(eWLAN_PAL_STATUS_SUCCESS != status)
         {
            HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                     "%s: Post TX re-sync MSG fail",__func__);
         }
      }
   }

   return;
}

/*==========================================================================
  @  Function Name
    WLANDXE_KickDxe

  @  Description
    Kick DXE when HDD TX time out happen

  @  Parameters
    NONE

  @  Return
    NONE

===========================================================================*/
void WLANDXE_KickDxe(void)
{
   HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_INFO,
               "%s: Kick Dxe for HDD TX timeout",__func__);
   /* Make wake up HW */
   dxeNotifySmsm(eWLAN_PAL_FALSE, eWLAN_PAL_TRUE);
   dxeNotifySmsm(eWLAN_PAL_TRUE, eWLAN_PAL_FALSE);
   DXTRACE(dxeTrace(WLANDXE_DMA_CHANNEL_MAX, TRACE_SMSM_NOTIFY,
                      TRACE_WLANDXE_VAR_ENABLE));
}

wpt_uint32 WLANDXE_SetupLogTransfer(wpt_uint64 bufferAddr, wpt_uint32 bufferLen)
{
   WLANDXE_ChannelCBType    *channelEntry;

   channelEntry = &tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_RX_FW_LOG];


   return dxeRXLogRefillRing(tempDxeCtrlBlk, channelEntry, bufferAddr,
                             bufferLen);
}

wpt_status WLANDXE_StartLogTransfer(void)
{
   WLANDXE_ChannelCBType    *channelEntry;
   wpt_status                status = eWLAN_PAL_STATUS_SUCCESS;

   channelEntry = &tempDxeCtrlBlk->dxeChannel[WDTS_CHANNEL_RX_FW_LOG];

   tempDxeCtrlBlk->hostInitiatedH2H = 1;
   status = wpalWriteRegister(channelEntry->channelRegister.chDXEDesclRegAddr,
                                   channelEntry->headCtrlBlk->linkedDescPhyAddr);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "%s Write DESC Address register fail", __func__);
      return status;
   }

   status = wpalWriteRegister(channelEntry->channelRegister.chDXECtrlRegAddr,
                          channelEntry->extraConfig.chan_mask);
   if(eWLAN_PAL_STATUS_SUCCESS != status)
   {
      HDXE_MSG(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
               "dxeChannelInitProgram Write RX Control register fail");
      return status;
   }
   return status;
}
