/******************************************************************************

 � 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
 All rights reserved.

 This is proprietary source code of Freescale Semiconductor Inc.,
 and its use is subject to the NetComm Device Drivers EULA.
 The copyright notice above does not evidence any actual or intended
 publication of such source code.

 ALTERNATIVELY, redistribution and use in source and binary forms, with
 or without modification, are permitted provided that the following
 conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
     * Neither the name of Freescale Semiconductor nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *

 **************************************************************************/
/******************************************************************************
 @File          qm.c

 @Description   QM & Portal implementation
*//***************************************************************************/

#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/atomic.h>
#include "error_ext.h"
#include "std_ext.h"
#include "string_ext.h"
#include "sprint_ext.h"
#include "mm_ext.h"
#include "core_ext.h"
#include "debug_ext.h"

#include "qm.h"


static volatile bool blockingFlag = FALSE;
static void QmIpcMsgCompletionCB(t_Handle   h_Module,
                                 uint8_t    *p_Msg,
                                 uint8_t    *p_Reply,
                                 uint32_t   replyLength,
                                 t_Error    status)
{
    SANITY_CHECK_RETURN(h_Module, E_INVALID_HANDLE);

    UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status);UNUSED(h_Module);
    blockingFlag = FALSE;
}

static t_Error QmHandleIpcMsgCB(t_Handle  h_Qm,
                                uint8_t   *p_Msg,
                                uint32_t  msgLength,
                                uint8_t   *p_Reply,
                                uint32_t  *p_ReplyLength)
{
    t_Qm            *p_Qm           = (t_Qm*)h_Qm;
    t_QmIpcMsg      *p_IpcMsg       = (t_QmIpcMsg*)p_Msg;
    t_QmIpcReply    *p_IpcReply   = (t_QmIpcReply *)p_Reply;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE);

#ifdef DISABLE_SANITY_CHECKS
    UNUSED(msgLength);
#endif /* DISABLE_SANITY_CHECKS */

    ASSERT_COND(p_IpcMsg);

    memset(p_IpcReply, 0, (sizeof(uint8_t) * QM_IPC_MAX_REPLY_SIZE));
    *p_ReplyLength = 0;

    switch(p_IpcMsg->msgId)
    {
        case (QM_MASTER_IS_ALIVE):
            *(uint8_t*)p_IpcReply->replyBody = 1;
            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t);
            break;
        case (QM_FORCE_FQID):
        {
            t_QmIpcFqidParams   ipcFqid;
            uint32_t            fqid;

            memcpy((uint8_t*)&ipcFqid, p_IpcMsg->msgBody, sizeof(t_QmIpcFqidParams));
            fqid = QmFqidGet(p_Qm, ipcFqid.size, 1, TRUE, ipcFqid.fqid);
            memcpy(p_IpcReply->replyBody, (uint8_t*)&fqid, sizeof(uint32_t));
            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
            break;
        }
        case (QM_PUT_FQID):
        {
            t_Error             err;
            t_QmIpcFqidParams   ipcFqid;

            memcpy((uint8_t*)&ipcFqid, p_IpcMsg->msgBody, sizeof(t_QmIpcFqidParams));
            if ((err = QmFqidPut(p_Qm, ipcFqid.fqid)) != E_OK)
                REPORT_ERROR(MINOR, err, NO_MSG);
            break;
        }
        case (QM_GET_COUNTER):
        {
            t_QmIpcGetCounter   ipcCounter;
            uint32_t            count;

            memcpy((uint8_t*)&ipcCounter, p_IpcMsg->msgBody, sizeof(t_QmIpcGetCounter));
            count = QmGetCounter(p_Qm, (e_QmInterModuleCounters)ipcCounter.enumId);
            memcpy(p_IpcReply->replyBody, (uint8_t*)&count, sizeof(uint32_t));
            *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t);
            break;
        }
        case (QM_GET_SET_PORTAL_PARAMS):
        {
            t_Error                         err;
            t_QmIpcPortalInitParams         ipcPortalInitParams;
            t_QmInterModulePortalInitParams portalInitParams;

            memcpy((uint8_t*)&ipcPortalInitParams, p_IpcMsg->msgBody, sizeof(t_QmIpcPortalInitParams));
            portalInitParams.portalId       = ipcPortalInitParams.portalId;
            portalInitParams.stashDestQueue = ipcPortalInitParams.stashDestQueue;
            portalInitParams.liodn          = ipcPortalInitParams.liodn;
            portalInitParams.dqrrLiodn      = ipcPortalInitParams.dqrrLiodn;
            portalInitParams.fdFqLiodn      = ipcPortalInitParams.fdFqLiodn;
            if ((err = QmGetSetPortalParams(p_Qm, &portalInitParams)) != E_OK)
                REPORT_ERROR(MINOR, err, NO_MSG);
            break;
        }
        case (QM_GET_REVISION):
        {
            t_QmRevisionInfo    revInfo;
            t_QmIpcRevisionInfo ipcRevInfo;

            p_IpcReply->error = (uint32_t)QmGetRevision(h_Qm, &revInfo);
            ipcRevInfo.majorRev = revInfo.majorRev;
            ipcRevInfo.minorRev = revInfo.minorRev;
            memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_QmIpcRevisionInfo));
            *p_ReplyLength = sizeof(uint32_t) + sizeof(t_QmIpcRevisionInfo);
            break;
        }
        default:
            *p_ReplyLength = 0;
            RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!"));
    }
    return E_OK;
}

static t_Error CheckQmParameters(t_Qm *p_Qm)
{
    if ((p_Qm->p_QmDriverParams->partFqidBase + p_Qm->p_QmDriverParams->partNumOfFqids) > QM_MAX_NUM_OF_FQIDS)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partFqidBase+partNumOfFqids out of range!!!"));
    if ((p_Qm->partCgsBase + p_Qm->partNumOfCgs) > QM_MAX_NUM_OF_CGS)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partCgsBase+partNumOfCgs out of range!!!"));

    if (p_Qm->guestId == NCSW_MASTER_ID)
    {
        uint64_t            phyAddr;

        phyAddr = XX_VirtToPhys(UINT_TO_PTR(p_Qm->p_QmDriverParams->swPortalsBaseAddress));

        if (phyAddr & 0x00000000001fffffLL)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("swPortalsBaseAddress isn't properly aligned"));
        if (!p_Qm->p_QmDriverParams->rtFramesDepth)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rtFramesDepth must be larger than '0'!!!"));
        if (p_Qm->p_QmDriverParams->rtFramesDepth > ((16*MEGABYTE)*3))
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("rtFramesDepth must be equal or smaller than 48MB!!!"));
        if (!p_Qm->p_QmDriverParams->totalNumOfFqids)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfFqids must be larger than '0'!!!"));
        if (p_Qm->p_QmDriverParams->totalNumOfFqids > (16*MEGABYTE))
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfFqids must be equal or smaller than 16MB!!!"));
        if(!p_Qm->f_Exception)
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided"));
    }

    return E_OK;
}

static t_Error QmInitPfdr(t_Qm *p_Qm, uint32_t pfdr_start, uint32_t num)
{
    uint8_t     rslt;
    uint32_t    timeout = 100000;

    ASSERT_COND(p_Qm);

    ASSERT_COND(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num);

    /* Make sure te command interface is 'idle' */
    rslt = MCR_get_rslt(GET_UINT32(p_Qm->p_QmRegs->mcr));
    if (!MCR_rslt_idle(rslt))
        RETURN_ERROR(CRITICAL,E_INVALID_STATE,("QMAN_MCR isn't idle"));

    /* Write the MCR command params then the verb */
    WRITE_UINT32(p_Qm->p_QmRegs->mcp0, pfdr_start);
    /* TODO: remove this - it's a workaround for a model bug that is
     * corrected in more recent versions. We use the workaround until
     * everyone has upgraded. */
    WRITE_UINT32(p_Qm->p_QmRegs->mcp1, (pfdr_start + num - 16));
    WRITE_UINT32(p_Qm->p_QmRegs->mcp1, (pfdr_start + num - 1));

    mb();
    WRITE_UINT32(p_Qm->p_QmRegs->mcr, MCR_INIT_PFDR);

    /* Poll for the result */
    do {
        XX_UDelay(1);
        rslt = MCR_get_rslt(GET_UINT32(p_Qm->p_QmRegs->mcr));
    } while(!MCR_rslt_idle(rslt) && --timeout);

    if (MCR_rslt_ok(rslt))
        return E_OK;
    WRITE_UINT32(p_Qm->p_QmRegs->mcr, 0);
    if (!timeout)
        RETURN_ERROR(MAJOR, E_TIMEOUT, NO_MSG);
    if (MCR_rslt_eaccess(rslt))
        RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG);
    if (MCR_rslt_inval(rslt))
        RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG);
    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unexpected result from MCR_INIT_PFDR: %02x\n", rslt));
}

static __inline__ void QmSetWqScheduling(t_Qm *p_Qm,
                                         e_QmWqClass wqClass,
                                         uint8_t csElev,
                                         uint8_t csw2,
                                         uint8_t csw3,
                                         uint8_t csw4,
                                         uint8_t csw5,
                                         uint8_t csw6,
                                         uint8_t csw7)
{
    ASSERT_COND(p_Qm);

    WRITE_UINT32(p_Qm->p_QmRegs->wq_cs_cfg[wqClass],
                 (uint32_t)(((csElev & 0xff) << 24) |
                 ((csw2 & 0x7) << 20) |
                 ((csw3 & 0x7) << 16) |
                 ((csw4 & 0x7) << 12) |
                 ((csw5 & 0x7) << 8) |
                 ((csw6 & 0x7) << 4) |
                 (csw7 & 0x7)));
}

static uint32_t ReserveFqids(t_Qm *p_Qm, uint32_t size, uint32_t alignment, bool force, uint32_t base)
{
    uint64_t    ans;
    uint32_t    intFlags;

    intFlags = XX_LockIntrSpinlock(p_Qm->lock);
    if (force)
        ans = MM_GetForce(p_Qm->h_FqidMm,
                          (uint64_t)base,
                          (uint64_t)size,
                          "QM FQID MEM");
    else
        ans = MM_Get(p_Qm->h_FqidMm,
                     (uint64_t)size,
                     alignment,
                     "QM FQID MEM");
    if (ans == ILLEGAL_BASE)
    {
        XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
        return (uint32_t)ans;
    }
    base = (uint32_t)ans;
    ans = MM_GetForce(p_Qm->h_RsrvFqidMm,
                      (uint64_t)base,
                      (uint64_t)size,
                      "QM rsrv FQID MEM");
    if (ans == ILLEGAL_BASE)
    {
        MM_Put(p_Qm->h_FqidMm, (uint64_t)base);
        XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
        return (uint32_t)ans;
    }
    XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);

    return (uint32_t)base;
}

static void FreeInitResources(t_Qm *p_Qm)
{
    if (p_Qm->p_FqdBase)
        XX_FreeSmart(p_Qm->p_FqdBase);
    if (p_Qm->p_PfdrBase)
        XX_FreeSmart(p_Qm->p_PfdrBase);
    if (p_Qm->h_Session)
        XX_IpcFreeSession(p_Qm->h_Session);
    if (p_Qm->h_RsrvFqidMm)
        MM_Free(p_Qm->h_RsrvFqidMm);
    if (p_Qm->h_FqidMm)
        MM_Free(p_Qm->h_FqidMm);
}


/****************************************/
/*       Inter-Module functions         */
/****************************************/

uint32_t QmGetCounter(t_Handle h_Qm, e_QmInterModuleCounters counter)
{
    t_Qm *p_Qm = (t_Qm*)h_Qm;

    SANITY_CHECK_RETURN_VALUE(p_Qm, E_INVALID_HANDLE, 0);
    SANITY_CHECK_RETURN_VALUE((((p_Qm->guestId == NCSW_MASTER_ID) && p_Qm->p_QmRegs) ||
                               (p_Qm->guestId != NCSW_MASTER_ID)), E_INVALID_STATE, 0);

    if ((p_Qm->guestId == NCSW_MASTER_ID) ||
        (!p_Qm->h_Session && p_Qm->p_QmRegs))
    {
        switch(counter)
        {
            case(e_QM_IM_COUNTERS_SFDR_IN_USE):
                return GET_UINT32(p_Qm->p_QmRegs->sfdr_in_use);
            case(e_QM_IM_COUNTERS_PFDR_IN_USE):
                return (p_Qm->numOfPfdr - GET_UINT32(p_Qm->p_QmRegs->pfdr_fpc));
            case(e_QM_IM_COUNTERS_PFDR_FREE_POOL):
                return (GET_UINT32(p_Qm->p_QmRegs->pfdr_fpc) - GET_UINT32(p_Qm->p_QmRegs->pfdr_cfg));
            default:
                break;
        }
        /* should never get here */
        ASSERT_COND(FALSE);
    }
    else if (p_Qm->h_Session)
    {
        t_QmIpcMsg              msg;
        t_QmIpcReply            reply;
        t_QmIpcGetCounter       ipcCounter;
        uint32_t                replyLength, count;
        t_Error                 errCode = E_OK;

        memset(&msg, 0, sizeof(t_QmIpcMsg));
        memset(&reply, 0, sizeof(t_QmIpcReply));
        ipcCounter.enumId       = (uint32_t)counter;
        msg.msgId               = QM_GET_COUNTER;
        memcpy(msg.msgBody, &ipcCounter, sizeof(t_QmIpcGetCounter));
        replyLength = sizeof(uint32_t) + sizeof(uint32_t);
        if ((errCode = XX_IpcSendMessage(p_Qm->h_Session,
                                         (uint8_t*)&msg,
                                         sizeof(msg.msgId) + sizeof(t_QmIpcGetCounter),
                                         (uint8_t*)&reply,
                                         &replyLength,
                                         NULL,
                                         NULL)) != E_OK)
            REPORT_ERROR(MAJOR, errCode, NO_MSG);
        if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
        if ((errCode == E_OK) && (replyLength == (sizeof(uint32_t) + sizeof(uint32_t))))
        {
            memcpy((uint8_t*)&count, reply.replyBody, sizeof(uint32_t));
            return count;
        }
    }
    else
        REPORT_ERROR(WARNING, E_NOT_SUPPORTED,
                     ("In 'guest', either IPC or 'baseAddress' is required!"));

    return 0;
}

t_Error QmGetRevision(t_Handle h_Qm, t_QmRevisionInfo *p_QmRevisionInfo)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;
    uint32_t    tmpReg;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_QmRevisionInfo, E_NULL_POINTER);
    SANITY_CHECK_RETURN_ERROR((((p_Qm->guestId == NCSW_MASTER_ID) && p_Qm->p_QmRegs) ||
                               (p_Qm->guestId != NCSW_MASTER_ID)), E_INVALID_STATE);

    if ((p_Qm->guestId == NCSW_MASTER_ID) ||
        (!p_Qm->h_Session && p_Qm->p_QmRegs))
    {
        /* read revision register 1 */
        tmpReg = GET_UINT32(p_Qm->p_QmRegs->ip_rev_1);
        p_QmRevisionInfo->majorRev = (uint8_t)((tmpReg & REV1_MAJOR_MASK) >> REV1_MAJOR_SHIFT);
        p_QmRevisionInfo->minorRev = (uint8_t)((tmpReg & REV1_MINOR_MASK) >> REV1_MINOR_SHIFT);
    }
    else if (p_Qm->h_Session)
    {
        t_QmIpcMsg          msg;
        t_QmIpcReply        reply;
        t_QmIpcRevisionInfo ipcRevInfo;
        uint32_t            replyLength;
        t_Error             errCode = E_OK;

        memset(&msg, 0, sizeof(t_QmIpcMsg));
        memset(&reply, 0, sizeof(reply));
        msg.msgId           = QM_GET_REVISION;
        replyLength = sizeof(uint32_t) + sizeof(t_QmIpcRevisionInfo);
        if ((errCode = XX_IpcSendMessage(p_Qm->h_Session,
                                         (uint8_t*)&msg,
                                         sizeof(msg.msgId),
                                         (uint8_t*)&reply,
                                         &replyLength,
                                         NULL,
                                         NULL)) != E_OK)
            RETURN_ERROR(MAJOR, errCode, NO_MSG);
        if (replyLength != (sizeof(uint32_t) + sizeof(t_QmIpcRevisionInfo)))
            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));

        memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_QmIpcRevisionInfo));
        p_QmRevisionInfo->majorRev = ipcRevInfo.majorRev;
        p_QmRevisionInfo->minorRev = ipcRevInfo.minorRev;

        return (t_Error)(reply.error);
    }
    else
        RETURN_ERROR(WARNING, E_NOT_SUPPORTED,
                     ("In 'guest', either IPC or 'baseAddress' is required!"));

    return E_OK;
}

t_Error QmGetSetPortalParams(t_Handle h_Qm, t_QmInterModulePortalInitParams *p_PortalParams)
{
    t_Qm                *p_Qm = (t_Qm *)h_Qm;
    t_QmRevisionInfo    revInfo;
    uint32_t            lioReg,ioReg;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_PortalParams, E_NULL_POINTER);

    if (p_Qm->guestId == NCSW_MASTER_ID)
    {
        QmGetRevision(p_Qm, &revInfo);

        if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0))
        {
            lioReg  = (uint32_t)(p_PortalParams->stashDestQueue << 24) |
                      (p_PortalParams->liodn << 16) |
                      (p_PortalParams->dqrrLiodn);
            ioReg   = (p_PortalParams->fdFqLiodn);
        }
        else
        {
            lioReg  = (uint32_t)(p_PortalParams->liodn << 16) |
                      (p_PortalParams->dqrrLiodn);
            ioReg   = (uint32_t)(p_PortalParams->stashDestQueue << 16) |
                      (p_PortalParams->fdFqLiodn);
        }

        WRITE_UINT32(p_Qm->p_QmRegs->swpConfRegs[p_PortalParams->portalId].lio_cfg, lioReg);
        WRITE_UINT32(p_Qm->p_QmRegs->swpConfRegs[p_PortalParams->portalId].io_cfg, ioReg);
    }
    else if (p_Qm->h_Session)
    {
        t_QmIpcMsg                  msg;
        t_QmIpcPortalInitParams     portalParams;
        t_Error                     errCode;

        memset(&msg, 0, sizeof(t_QmIpcMsg));
        portalParams.portalId       = p_PortalParams->portalId;
        portalParams.stashDestQueue = p_PortalParams->stashDestQueue;
        portalParams.liodn          = p_PortalParams->liodn;
        portalParams.dqrrLiodn      = p_PortalParams->dqrrLiodn;
        portalParams.fdFqLiodn      = p_PortalParams->fdFqLiodn;
        msg.msgId           = QM_GET_SET_PORTAL_PARAMS;
        memcpy(msg.msgBody, &portalParams, sizeof(t_QmIpcPortalInitParams));
        XX_LockSpinlock(p_Qm->lock);
        if ((errCode = XX_IpcSendMessage(p_Qm->h_Session,
                                         (uint8_t*)&msg,
                                         sizeof(msg.msgId) + sizeof(t_QmIpcPortalInitParams),
                                         NULL,
                                         NULL,
                                         NULL,
                                         NULL)) != E_OK)
        {
            XX_UnlockSpinlock(p_Qm->lock);
            RETURN_ERROR(MAJOR, errCode, NO_MSG);
        }
        XX_UnlockSpinlock(p_Qm->lock);
    }
    else
        DBG(WARNING, ("Can't set portal parameters (e.g. liodns). " \
                      "probably QM is running in guest-mode with no IPC!"));

    return E_OK;
}

uint32_t QmFqidGet(t_Qm *p_Qm, uint32_t size, uint32_t alignment, bool force, uint32_t base)
{
    uint64_t    ans;
    uint32_t    intFlags;

    intFlags = XX_LockIntrSpinlock(p_Qm->lock);
    if (force)
    {
        ans = MM_GetForce(p_Qm->h_FqidMm,
                          (uint64_t)base,
                          (uint64_t)size,
                          "QM FQID MEM");
        if (ans == ILLEGAL_BASE)
        {
            ans = MM_GetForce(p_Qm->h_RsrvFqidMm,
                              (uint64_t)base,
                              (uint64_t)size,
                              "QM rsrv FQID MEM");
            if (ans == ILLEGAL_BASE)
                ans = base;
            else if (p_Qm->h_Session)
            {
                t_QmIpcMsg              msg;
                t_QmIpcReply            reply;
                uint32_t                replyLength;
                t_QmIpcFqidParams       ipcFqid;
                t_Error                 errCode = E_OK;

                memset(&msg, 0, sizeof(t_QmIpcMsg));
                memset(&reply, 0, sizeof(t_QmIpcReply));
                ipcFqid.fqid        = base;
                ipcFqid.size        = size;
                msg.msgId           = QM_FORCE_FQID;
                memcpy(msg.msgBody, &ipcFqid, sizeof(t_QmIpcFqidParams));
                replyLength = sizeof(uint32_t) + sizeof(uint32_t);
                if ((errCode = XX_IpcSendMessage(p_Qm->h_Session,
                                                 (uint8_t*)&msg,
                                                 sizeof(msg.msgId) + sizeof(t_QmIpcFqidParams),
                                                 (uint8_t*)&reply,
                                                 &replyLength,
                                                 NULL,
                                                 NULL)) != E_OK)
                    REPORT_ERROR(MAJOR, errCode, NO_MSG);
                if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t)))
                   REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));

                if ((errCode != E_OK) ||
                    (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))))
                    ans = ILLEGAL_BASE;
                else
                    memcpy((uint8_t*)&ans, reply.replyBody, sizeof(uint32_t));
            }
            else
            {
                DBG(WARNING, ("No Ipc - can't validate fqid."));
                ans = base;
            }
        }
    }
    else
        ans = MM_Get(p_Qm->h_FqidMm,
                     size,
                     alignment,
                     "QM FQID MEM");
    XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);

    KASSERT(ans < UINT32_MAX, ("Oops, %jx > UINT32_MAX!\n", (uintmax_t)ans));
    return (uint32_t)ans;
}

t_Error QmFqidPut(t_Qm *p_Qm, uint32_t base)
{
    uint32_t    intFlags;

    intFlags = XX_LockIntrSpinlock(p_Qm->lock);
    /* Check maybe this fqid was reserved in the past */
    if (MM_GetForce(p_Qm->h_RsrvFqidMm,
                    (uint64_t)base,
                    (uint64_t)1,
                    "QM rsrv FQID MEM") == ILLEGAL_BASE)
    {
        XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
        return E_OK;
    }
    else
        MM_PutForce(p_Qm->h_RsrvFqidMm,
                    (uint64_t)base,
                    (uint64_t)1);
    if (MM_InRange(p_Qm->h_FqidMm, (uint64_t)base))
    {
        if (MM_Put(p_Qm->h_FqidMm, (uint64_t)base) != 0)
        {
            XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
            return E_OK;
        }
        else
        {
            XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
            return ERROR_CODE(E_NOT_FOUND);
        }
    }
    else if (p_Qm->h_Session)
    {
        t_QmIpcMsg              msg;
        t_QmIpcFqidParams       ipcFqid;
        t_Error                 errCode = E_OK;

        memset(&msg, 0, sizeof(t_QmIpcMsg));
        ipcFqid.fqid        = (uint8_t)base;
        ipcFqid.size        = 0;
        msg.msgId           = QM_PUT_FQID;
        memcpy(msg.msgBody, &ipcFqid, sizeof(t_QmIpcFqidParams));
        if ((errCode = XX_IpcSendMessage(p_Qm->h_Session,
                                         (uint8_t*)&msg,
                                         sizeof(msg.msgId) + sizeof(t_QmIpcFqidParams),
                                         NULL,
                                         NULL,
                                         NULL,
                                         NULL)) != E_OK)
        {
            XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);
            RETURN_ERROR(MAJOR, errCode, NO_MSG);
        }
    }
    else
        DBG(WARNING, ("No Ipc - can't validate fqid."));
    XX_UnlockIntrSpinlock(p_Qm->lock, intFlags);

    return E_OK;
}

t_Error QmGetCgId(t_Handle h_Qm, uint8_t *p_CgId)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;
    uint16_t    i;

    for(i = p_Qm->partCgsBase;i<p_Qm->partCgsBase+p_Qm->partNumOfCgs;i++)
        if (!p_Qm->cgsUsed[i])
        {
            p_Qm->cgsUsed[i] = (uint8_t)TRUE;
            *p_CgId = (uint8_t)i;
            break;
        }
    if(i == (p_Qm->partCgsBase+p_Qm->partNumOfCgs))
        RETURN_ERROR(MINOR, E_BUSY, ("No available CG"));
    else
        return E_OK;
}

t_Error QmFreeCgId(t_Handle h_Qm, uint8_t cgId)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;

    if (!p_Qm->cgsUsed[cgId])
        RETURN_ERROR(MINOR, E_INVALID_STATE, ("CG is not in use"));
    else
        p_Qm->cgsUsed[cgId] = (uint8_t)FALSE;

    return E_OK;
}


/****************************************/
/*       API Init unit functions        */
/****************************************/

t_Handle QM_Config(t_QmParam *p_QmParam)
{
    t_Qm    *p_Qm;
    uint8_t i;

    SANITY_CHECK_RETURN_VALUE(p_QmParam, E_INVALID_HANDLE, NULL);

    p_Qm = (t_Qm *)XX_Malloc(sizeof(t_Qm));
    if (!p_Qm)
    {
        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("QM obj!!!"));
        return NULL;
    }
    memset(p_Qm, 0, sizeof(t_Qm));
    p_Qm->p_QmDriverParams = (t_QmDriverParams *)XX_Malloc(sizeof(t_QmDriverParams));
    if (!p_Qm->p_QmDriverParams)
    {
        XX_Free(p_Qm);
        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Qm driver parameters"));
        return NULL;
    }
    memset(p_Qm->p_QmDriverParams, 0, sizeof(t_QmDriverParams));

    p_Qm->guestId                           = p_QmParam->guestId;
    p_Qm->p_QmDriverParams->partFqidBase    = p_QmParam->partFqidBase;
    p_Qm->p_QmDriverParams->partNumOfFqids  = p_QmParam->partNumOfFqids;
    p_Qm->partCgsBase                       = p_QmParam->partCgsBase;
    p_Qm->partNumOfCgs                      = p_QmParam->partNumOfCgs;
    p_Qm->p_QmRegs                          = (t_QmRegs *)UINT_TO_PTR(p_QmParam->baseAddress);

    if (p_Qm->guestId == NCSW_MASTER_ID)
    {
        p_Qm->exceptions        = DEFAULT_exceptions;
        p_Qm->f_Exception       = p_QmParam->f_Exception;
        p_Qm->h_App             = p_QmParam->h_App;
        p_Qm->errIrq            = p_QmParam->errIrq;
        p_Qm->p_QmDriverParams->liodn                   = p_QmParam->liodn;
        p_Qm->p_QmDriverParams->rtFramesDepth           = DEFAULT_rtFramesDepth;
        p_Qm->p_QmDriverParams->fqdMemPartitionId       = p_QmParam->fqdMemPartitionId;
        p_Qm->p_QmDriverParams->pfdrMemPartitionId      = p_QmParam->pfdrMemPartitionId;
        p_Qm->p_QmDriverParams->swPortalsBaseAddress    = p_QmParam->swPortalsBaseAddress;
        p_Qm->p_QmDriverParams->totalNumOfFqids         = p_QmParam->totalNumOfFqids;
        p_Qm->p_QmDriverParams->pfdrThreshold           = DEFAULT_pfdrThreshold;
        p_Qm->p_QmDriverParams->sfdrThreshold           = DEFAULT_sfdrThreshold;
        p_Qm->p_QmDriverParams->pfdrBaseConstant        = DEFAULT_pfdrBaseConstant;
        for(i= 0;i<DPAA_MAX_NUM_OF_DC_PORTALS;i++)
            p_Qm->p_QmDriverParams->dcPortalsParams[i].sendToSw =
                (bool)((i < e_DPAA_DCPORTAL2) ? FALSE : TRUE);

#ifdef QMAN_SFDR_LEAK_ERRATA_QMAN5
        {
#define WORKAROUND_TMP_VAL  0x00000003
        t_QmRevisionInfo revInfo;
        QmGetRevision(p_Qm, &revInfo);
        if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0))
        {
            uint32_t *tmp = (uint32_t *)UINT_TO_PTR(p_QmParam->baseAddress + 0xbf0);
            uint32_t tmpReg = WORKAROUND_TMP_VAL;
            WRITE_UINT32(*tmp, tmpReg);
            while ((tmpReg = GET_UINT32(*tmp)) != WORKAROUND_TMP_VAL) ;
        }
        }
#endif /* QMAN_SFDR_LEAK_ERRATA_QMAN5 */
    }

    /* build the QM partition IPC address */
    memset(p_Qm->moduleName, 0, MODULE_NAME_SIZE);
    if(Sprint (p_Qm->moduleName, "QM_0_%d",p_Qm->guestId) != (p_Qm->guestId<10 ? 6:7))
    {
        XX_Free(p_Qm->p_QmDriverParams);
        XX_Free(p_Qm);
        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
        return NULL;
    }

    return p_Qm;
}

t_Error QM_Init(t_Handle h_Qm)
{
    t_Qm                *p_Qm = (t_Qm *)h_Qm;
    t_QmDriverParams    *p_QmDriverParams;
    t_Error             err;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    CHECK_INIT_PARAMETERS(p_Qm, CheckQmParameters);

    p_QmDriverParams        = p_Qm->p_QmDriverParams;

    if (p_QmDriverParams->partNumOfFqids)
    {
        if (MM_Init(&p_Qm->h_FqidMm, p_QmDriverParams->partFqidBase, p_QmDriverParams->partNumOfFqids) != E_OK)
            RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("QM-FQIDS-MEM partition!!!"));
        if (MM_Init(&p_Qm->h_RsrvFqidMm, p_QmDriverParams->partFqidBase, p_QmDriverParams->partNumOfFqids) != E_OK)
            RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("QM-Reserve-FQIDS-MEM partition!!!"));
    }

    if (p_Qm->guestId == NCSW_MASTER_ID)
    {
        uint64_t            phyAddr;
        t_QmRevisionInfo    revInfo;
        uint32_t            dsSize, exp, i;

        QmGetRevision(p_Qm, &revInfo);
        DBG(TRACE, ("Qman ver:%02x,%02x", revInfo.majorRev, revInfo.minorRev));

        phyAddr = XX_VirtToPhys(UINT_TO_PTR(p_QmDriverParams->swPortalsBaseAddress));
        WRITE_UINT32(p_Qm->p_QmRegs->qcsp_bare, ((uint32_t)(phyAddr >> 32) & 0x000000ff));
        WRITE_UINT32(p_Qm->p_QmRegs->qcsp_bar, (uint32_t)phyAddr);
        WRITE_UINT32(p_Qm->p_QmRegs->liodnr, (uint16_t)p_QmDriverParams->liodn);

        /* FQD memory */
        dsSize = (uint32_t)(p_QmDriverParams->totalNumOfFqids * FQD_ENTRY_SIZE);
        LOG2(dsSize, exp);
        if (!POWER_OF_2(dsSize)) (exp++);
        dsSize = (uint32_t)(1 << exp);
        if (dsSize < (4*KILOBYTE))
        {
            dsSize = (4*KILOBYTE);
            LOG2(dsSize, exp);
        }
        p_Qm->p_FqdBase = XX_MallocSmart(dsSize, (int)p_QmDriverParams->fqdMemPartitionId, dsSize);
        if (!p_Qm->p_FqdBase)
        {
            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FQD obj!!!"));
        }
        memset(p_Qm->p_FqdBase, 0, dsSize);
	mb();
        for (i=0; i<dsSize; i+=64)
            dcbf(PTR_MOVE(p_Qm->p_FqdBase, i));
	mb();

        phyAddr = XX_VirtToPhys(p_Qm->p_FqdBase);
        WRITE_UINT32(p_Qm->p_QmRegs->fqd_bare, ((uint32_t)(phyAddr >> 32) & 0x000000ff));
        WRITE_UINT32(p_Qm->p_QmRegs->fqd_bar, (uint32_t)phyAddr);
        WRITE_UINT32(p_Qm->p_QmRegs->fqd_ar, AR_ENABLE | (exp - 1));

        /* PFDR memory */
        dsSize = (uint32_t)(p_QmDriverParams->rtFramesDepth * (PFDR_ENTRY_SIZE/3));
        LOG2(dsSize, exp);
        if (!POWER_OF_2(dsSize)) (exp++);
        dsSize = (uint32_t)(1 << exp);
        if (dsSize < (4*KILOBYTE))
        {
            dsSize = (4*KILOBYTE);
            LOG2(dsSize, exp);
        }

        p_Qm->p_PfdrBase = XX_MallocSmart(dsSize, (int)p_QmDriverParams->pfdrMemPartitionId, dsSize);
        if (!p_Qm->p_PfdrBase)
            RETURN_ERROR(MAJOR, E_NO_MEMORY, ("PFDR obj!!!"));

        phyAddr = XX_VirtToPhys(p_Qm->p_PfdrBase);
        WRITE_UINT32(p_Qm->p_QmRegs->pfdr_bare, ((uint32_t)(phyAddr >> 32) & 0x000000ff));
        WRITE_UINT32(p_Qm->p_QmRegs->pfdr_bar, (uint32_t)phyAddr);
        WRITE_UINT32(p_Qm->p_QmRegs->pfdr_ar, AR_ENABLE | (exp - 1));

        if (QmInitPfdr(p_Qm, 8, dsSize / 64 - 8) != E_OK)
            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("PFDR init failed!!!"));

        /* thresholds */
        WRITE_UINT32(p_Qm->p_QmRegs->pfdr_fp_lwit, (p_Qm->p_QmDriverParams->pfdrThreshold & 0xffffff));
        WRITE_UINT32(p_Qm->p_QmRegs->pfdr_cfg, p_Qm->p_QmDriverParams->pfdrBaseConstant);
        WRITE_UINT32(p_Qm->p_QmRegs->sfdr_cfg, (p_Qm->p_QmDriverParams->sfdrThreshold & 0x3ff));

        p_Qm->numOfPfdr = GET_UINT32(p_Qm->p_QmRegs->pfdr_fpc);

        /* corenet initiator settings */
        WRITE_UINT32(p_Qm->p_QmRegs->ci_sched_cfg,
                     (CI_SCHED_CFG_EN |
                     (DEFAULT_initiatorSrcciv << CI_SCHED_CFG_SRCCIV_SHIFT) |
                     (DEFAULT_initiatorSrqW << CI_SCHED_CFG_SRQ_W_SHIFT) |
                     (DEFAULT_initiatorRwW << CI_SCHED_CFG_RW_W_SHIFT) |
                     (DEFAULT_initiatorBmanW << CI_SCHED_CFG_BMAN_W_SHIFT)));

        /* HID settings */
        if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0))
            /* offset 0x0bf0 */
            WRITE_UINT32(p_Qm->p_QmRegs->res23[144], 0x3);
        else
            WRITE_UINT32(p_Qm->p_QmRegs->res23[144], 0x0);

        for(i=0;i<DPAA_MAX_NUM_OF_DC_PORTALS;i++)
        {
            if(p_Qm->p_QmDriverParams->dcPortalsParams[i].sendToSw)
                WRITE_UINT32(p_Qm->p_QmRegs->dcpConfRegs[i].cfg,
                    p_Qm->p_QmDriverParams->dcPortalsParams[i].swPortalId);
            else
                WRITE_UINT32(p_Qm->p_QmRegs->dcpConfRegs[i].cfg, QM_DCP_CFG_ED);
        }

#ifdef QMAN_WQ_CS_CFG_ERRATA_QMAN4
        {
            t_QmRevisionInfo revInfo;
            QmGetRevision(p_Qm, &revInfo);
            if ((revInfo.majorRev == 1) && (revInfo.minorRev == 0))
            {
                QmSetWqScheduling(p_Qm, e_QM_WQ_SW_PORTALS,0,1,1,1,1,1,1);
                QmSetWqScheduling(p_Qm, e_QM_WQ_POOLS,0,1,1,1,1,1,1);
                QmSetWqScheduling(p_Qm, e_QM_WQ_DCP0,0,1,1,1,1,1,1);
                QmSetWqScheduling(p_Qm, e_QM_WQ_DCP1,0,1,1,1,1,1,1);
                QmSetWqScheduling(p_Qm, e_QM_WQ_DCP2,0,1,1,1,1,1,1);
                QmSetWqScheduling(p_Qm, e_QM_WQ_DCP3,0,1,1,1,1,1,1);
            }
        }
#endif /* QMAN_WQ_CS_CFG_ERRATA_QMAN4 */

        WRITE_UINT32(p_Qm->p_QmRegs->err_isr, p_Qm->exceptions);
        WRITE_UINT32(p_Qm->p_QmRegs->err_ier, p_Qm->exceptions);
        WRITE_UINT32(p_Qm->p_QmRegs->err_isdr, 0x0);
        if (p_Qm->errIrq != NO_IRQ)
        {
            XX_SetIntr(p_Qm->errIrq, QM_ErrorIsr, p_Qm);
            XX_EnableIntr(p_Qm->errIrq);
        }
        if ((err = XX_IpcRegisterMsgHandler(p_Qm->moduleName, QmHandleIpcMsgCB, p_Qm, QM_IPC_MAX_REPLY_SIZE)) != E_OK)
            RETURN_ERROR(MAJOR, err, NO_MSG);
    }
    else /* guest mode */
    {
        char                    masterModuleName[MODULE_NAME_SIZE];

        memset(masterModuleName, 0, MODULE_NAME_SIZE);
        if(Sprint (masterModuleName, "QM_0_%d", NCSW_MASTER_ID) != (NCSW_MASTER_ID<10 ? 6:7))
        {
            RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed"));
        }

        p_Qm->h_Session     = XX_IpcInitSession(masterModuleName, p_Qm->moduleName);
        if (p_Qm->h_Session)
        {
            t_QmIpcMsg              msg;
            uint8_t                 isMasterAlive = 0;
            t_QmIpcReply            reply;
            uint32_t                replyLength;

            memset(&msg, 0, sizeof(t_QmIpcMsg));
            memset(&reply, 0, sizeof(t_QmIpcReply));
            msg.msgId   = QM_MASTER_IS_ALIVE;
            do
            {
                blockingFlag = TRUE;
                replyLength = sizeof(uint32_t) + sizeof(uint8_t);
                if ((err = XX_IpcSendMessage(p_Qm->h_Session,
                                             (uint8_t*)&msg,
                                             sizeof(msg.msgId),
                                             (uint8_t*)&reply,
                                             &replyLength,
                                             QmIpcMsgCompletionCB,
                                             p_Qm)) != E_OK)
                    REPORT_ERROR(MAJOR, err, NO_MSG);
                while(blockingFlag) ;
                if(replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))
                    REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
                isMasterAlive = *(uint8_t*)(reply.replyBody);
            } while (!isMasterAlive);
        }
    }

    p_Qm->lock = XX_InitSpinlock();
    XX_Free(p_Qm->p_QmDriverParams);
    p_Qm->p_QmDriverParams = NULL;

    return E_OK;
}

t_Error QM_Free(t_Handle h_Qm)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);

    if (p_Qm->lock)
        XX_FreeSpinlock(p_Qm->lock);

    if (p_Qm->guestId == NCSW_MASTER_ID)
    {
        XX_IpcUnregisterMsgHandler(p_Qm->moduleName);
        if (p_Qm->errIrq  != NO_IRQ)
        {
            XX_DisableIntr(p_Qm->errIrq);
            XX_FreeIntr(p_Qm->errIrq);
        }
    }
    FreeInitResources(p_Qm);

    if (p_Qm->p_QmDriverParams)
        XX_Free(p_Qm->p_QmDriverParams);

    XX_Free(p_Qm);

    return E_OK;
}

t_Error QM_ConfigRTFramesDepth(t_Handle h_Qm, uint32_t rtFramesDepth)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    p_Qm->p_QmDriverParams->rtFramesDepth = rtFramesDepth;

    return E_OK;
}

t_Error QM_ConfigPfdrThreshold(t_Handle h_Qm, uint32_t threshold)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    p_Qm->p_QmDriverParams->pfdrThreshold = threshold;

    return E_OK;
}

t_Error QM_ConfigSfdrReservationThreshold(t_Handle h_Qm, uint32_t threshold)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    p_Qm->p_QmDriverParams->sfdrThreshold = threshold;

    return E_OK;
}


t_Error QM_ConfigErrorRejectionNotificationDest(t_Handle h_Qm, e_DpaaDcPortal id, t_QmDcPortalParams *p_Params)
{
    UNUSED(h_Qm); UNUSED(id); UNUSED(p_Params);

    RETURN_ERROR(INFO, E_NOT_SUPPORTED, ("Only default ERN destination available."));
}


t_Error QM_Poll(t_Handle h_Qm, e_QmPortalPollSource source)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;
    t_QmPortal  *p_QmPortal;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    p_QmPortal = QmGetPortalHandle(p_Qm);
    SANITY_CHECK_RETURN_ERROR(p_QmPortal, E_INVALID_HANDLE);

    return QM_PORTAL_Poll(p_QmPortal, source);
}

uint32_t QM_GetCounter(t_Handle h_Qm, e_QmCounters counter)
{
    t_Qm    *p_Qm = (t_Qm *)h_Qm;

    SANITY_CHECK_RETURN_VALUE(p_Qm, E_INVALID_HANDLE, 0);
    SANITY_CHECK_RETURN_VALUE(!p_Qm->p_QmDriverParams, E_INVALID_STATE, 0);

    switch(counter)
    {
        case(e_QM_COUNTERS_SFDR_IN_USE):
            return QmGetCounter(p_Qm, e_QM_IM_COUNTERS_SFDR_IN_USE);
        case(e_QM_COUNTERS_PFDR_IN_USE):
            return QmGetCounter(p_Qm, e_QM_IM_COUNTERS_PFDR_IN_USE);
        case(e_QM_COUNTERS_PFDR_FREE_POOL):
            return QmGetCounter(p_Qm, e_QM_IM_COUNTERS_PFDR_FREE_POOL);
        default:
            break;
    }
    /* should never get here */
    ASSERT_COND(FALSE);

    return 0;
}

void QM_ErrorIsr(t_Handle h_Qm)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;
    uint32_t    tmpReg;

    SANITY_CHECK_RETURN(p_Qm, E_INVALID_HANDLE);

    if (p_Qm->guestId != NCSW_MASTER_ID)
    {
        REPORT_ERROR(WARNING, E_INVALID_OPERATION, ("Master Only"));
        return;
    }

    tmpReg = GET_UINT32(p_Qm->p_QmRegs->err_isr);
    tmpReg &= GET_UINT32(p_Qm->p_QmRegs->err_ier);
    WRITE_UINT32(p_Qm->p_QmRegs->err_isr, tmpReg);

    if (tmpReg & QM_EX_CORENET_INITIATOR_DATA)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_CORENET_INITIATOR_DATA);
    if (tmpReg & QM_EX_CORENET_TARGET_DATA)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_CORENET_TARGET_DATA);
    if (tmpReg & QM_EX_CORENET_INVALID_TARGET_TRANSACTION)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION);
    if (tmpReg & QM_EX_PFDR_THRESHOLD)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_PFDR_THRESHOLD);
    if (tmpReg & QM_EX_MULTI_ECC)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_MULTI_ECC);
    if (tmpReg & QM_EX_SINGLE_ECC)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_SINGLE_ECC);
    if (tmpReg & QM_EX_PFDR_ENQUEUE_BLOCKED)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_PFDR_ENQUEUE_BLOCKED);
    if (tmpReg & QM_EX_INVALID_COMMAND)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_INVALID_COMMAND);
    if (tmpReg & QM_EX_DEQUEUE_DCP)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_DEQUEUE_DCP);
    if (tmpReg & QM_EX_DEQUEUE_FQ)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_DEQUEUE_FQ);
    if (tmpReg & QM_EX_DEQUEUE_SOURCE)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_DEQUEUE_SOURCE);
    if (tmpReg & QM_EX_DEQUEUE_QUEUE)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_DEQUEUE_QUEUE);
    if (tmpReg & QM_EX_ENQUEUE_OVERFLOW)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_ENQUEUE_OVERFLOW);
    if (tmpReg & QM_EX_ENQUEUE_STATE)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_ENQUEUE_STATE);
    if (tmpReg & QM_EX_ENQUEUE_CHANNEL)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_ENQUEUE_CHANNEL);
    if (tmpReg & QM_EX_ENQUEUE_QUEUE)
        p_Qm->f_Exception(p_Qm->h_App, e_QM_EX_ENQUEUE_QUEUE);
}

t_Error QM_SetException(t_Handle h_Qm, e_QmExceptions exception, bool enable)
{
    t_Qm                *p_Qm = (t_Qm*)h_Qm;
    t_Error             err = E_OK;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(!p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    if ((err = SetException(p_Qm, exception, enable)) != E_OK)
        RETURN_ERROR(MINOR, err, NO_MSG);

    WRITE_UINT32(p_Qm->p_QmRegs->err_ier, p_Qm->exceptions);

    return E_OK;
}

t_Error QM_GetRevision(t_Handle h_Qm, t_QmRevisionInfo *p_QmRevisionInfo)
{
    t_Qm        *p_Qm = (t_Qm*)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_QmRevisionInfo, E_NULL_POINTER);

    return QmGetRevision(p_Qm, p_QmRevisionInfo);
}

t_Error QM_ReserveQueues(t_Handle h_Qm, t_QmRsrvFqrParams *p_QmFqrParams, uint32_t  *p_BaseFqid)
{
    t_Qm                *p_Qm = (t_Qm*)h_Qm;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(!p_Qm->p_QmDriverParams, E_INVALID_HANDLE);

    *p_BaseFqid = ReserveFqids(p_Qm,
                               (uint32_t)((p_QmFqrParams->useForce && !p_QmFqrParams->numOfFqids) ?
                                          1 : p_QmFqrParams->numOfFqids),
                               p_QmFqrParams->qs.nonFrcQs.align,
                               p_QmFqrParams->useForce,
                               p_QmFqrParams->qs.frcQ.fqid);
    if (*p_BaseFqid == ILLEGAL_BASE)
        RETURN_ERROR(CRITICAL,E_INVALID_STATE,("can't allocate a fqid"));

    return E_OK;
}

t_Error QM_GetErrorInformation(t_Handle h_Qm, t_QmErrorInfo *p_errInfo)
{
    uint32_t            ecsr, ecir;
    t_Qm                *p_Qm = (t_Qm*)h_Qm;
    t_Error             err = E_OK;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(!p_Qm->p_QmDriverParams, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(p_errInfo, E_NULL_POINTER);

    ecsr = GET_UINT32(p_Qm->p_QmRegs->ecsr);
    ecir = GET_UINT32(p_Qm->p_QmRegs->ecir);
    if ((ecsr & QM_EX_MULTI_ECC) ||
        (ecsr & QM_EX_SINGLE_ECC))
    {
        err = E_NOT_SUPPORTED;
        REPORT_ERROR(INFO, E_NOT_SUPPORTED, ("single and multi ecc, use QM_DumpRegs"));
    }
    if ((ecsr & QM_EX_ENQUEUE_QUEUE)    ||
        (ecsr & QM_EX_ENQUEUE_STATE)    ||
        (ecsr & QM_EX_ENQUEUE_OVERFLOW) ||
        (ecsr & QM_EX_DEQUEUE_DCP)      ||
        (ecsr & QM_EX_DEQUEUE_FQ)       ||
        (ecsr & QM_EX_DEQUEUE_QUEUE)    ||
        (ecsr & QM_EX_DEQUEUE_SOURCE)   ||
        (ecsr & QM_EX_INVALID_COMMAND))
    {
        p_errInfo->portalValid = TRUE;
        p_errInfo->hwPortal = (bool)(ecir & ECIR_PORTAL_TYPE);
        if (p_errInfo->hwPortal)
            p_errInfo->dcpId = (e_DpaaDcPortal)((ecir & ECIR_PORTAL_MASK) >> ECIR_PORTAL_SHIFT);
        else
            p_errInfo->swPortalId = (e_DpaaSwPortal)((ecir & ECIR_PORTAL_MASK) >> ECIR_PORTAL_SHIFT);
    }

    if ((ecsr & QM_EX_ENQUEUE_QUEUE)    ||
        (ecsr & QM_EX_ENQUEUE_STATE)    ||
        (ecsr & QM_EX_ENQUEUE_OVERFLOW) ||
        (ecsr & QM_EX_ENQUEUE_CHANNEL)  ||
        (ecsr & QM_EX_DEQUEUE_QUEUE)    ||
        (ecsr & QM_EX_DEQUEUE_FQ))
    {
        p_errInfo->fqidValid = TRUE;
        p_errInfo->fqid = ((ecir & ECIR_FQID_MASK) >> ECIR_FQID_SHIFT);
    }

    WRITE_UINT32(p_Qm->p_QmRegs->ecsr, ecsr);

    return ERROR_CODE(err);
}

#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
t_Error QM_DumpRegs(t_Handle h_Qm)
{
    t_Qm        *p_Qm = (t_Qm *)h_Qm;
    uint8_t     i = 0;

    DECLARE_DUMP;

    SANITY_CHECK_RETURN_ERROR(p_Qm, E_INVALID_HANDLE);
    SANITY_CHECK_RETURN_ERROR(!p_Qm->p_QmDriverParams, E_INVALID_STATE);

    DUMP_SUBTITLE(("\n"));
    DUMP_TITLE(p_Qm->p_QmRegs, ("QmRegs Regs"));

    DUMP_SUBSTRUCT_ARRAY(i, QM_NUM_OF_SWP)
    {
        DUMP_VAR(&p_Qm->p_QmRegs->swpConfRegs[i], lio_cfg);
        DUMP_VAR(&p_Qm->p_QmRegs->swpConfRegs[i], io_cfg);
        DUMP_VAR(&p_Qm->p_QmRegs->swpConfRegs[i], dd_cfg);
    }
    DUMP_VAR(p_Qm->p_QmRegs, qman_dd_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, qcsp_dd_ihrsr);
    DUMP_VAR(p_Qm->p_QmRegs, qcsp_dd_ihrfr);
    DUMP_VAR(p_Qm->p_QmRegs, qcsp_dd_hasr);
    DUMP_VAR(p_Qm->p_QmRegs, dcp_dd_ihrsr);
    DUMP_VAR(p_Qm->p_QmRegs, dcp_dd_ihrfr);
    DUMP_VAR(p_Qm->p_QmRegs, dcp_dd_hasr);
    DUMP_SUBSTRUCT_ARRAY(i, QM_NUM_OF_DCP)
    {
        DUMP_VAR(&p_Qm->p_QmRegs->dcpConfRegs[i], cfg);
        DUMP_VAR(&p_Qm->p_QmRegs->dcpConfRegs[i], dd_cfg);
        DUMP_VAR(&p_Qm->p_QmRegs->dcpConfRegs[i], dlm_cfg);
        DUMP_VAR(&p_Qm->p_QmRegs->dcpConfRegs[i], dlm_avg);
    }
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_fpc);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_fp_head);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_fp_tail);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_fp_lwit);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, sfdr_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, sfdr_in_use);
    DUMP_ARR(p_Qm->p_QmRegs, wq_cs_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, wq_def_enq_wqid);
    DUMP_ARR(p_Qm->p_QmRegs, wq_sc_dd_cfg);
    DUMP_ARR(p_Qm->p_QmRegs, wq_pc_dd_cs_cfg);
    DUMP_ARR(p_Qm->p_QmRegs, wq_dc0_dd_cs_cfg);
    DUMP_ARR(p_Qm->p_QmRegs, wq_dc1_dd_cs_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, wq_dc2_dd_cs_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, wq_dc3_dd_cs_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, cm_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, ecsr);
    DUMP_VAR(p_Qm->p_QmRegs, ecir);
    DUMP_VAR(p_Qm->p_QmRegs, eadr);
    DUMP_ARR(p_Qm->p_QmRegs, edata);
    DUMP_VAR(p_Qm->p_QmRegs, sbet);
    DUMP_ARR(p_Qm->p_QmRegs, sbec);
    DUMP_VAR(p_Qm->p_QmRegs, mcr);
    DUMP_VAR(p_Qm->p_QmRegs, mcp0);
    DUMP_VAR(p_Qm->p_QmRegs, mcp1);
    DUMP_ARR(p_Qm->p_QmRegs, mr);
    DUMP_VAR(p_Qm->p_QmRegs, idle_stat);
    DUMP_VAR(p_Qm->p_QmRegs, ip_rev_1);
    DUMP_VAR(p_Qm->p_QmRegs, ip_rev_2);
    DUMP_VAR(p_Qm->p_QmRegs, fqd_bare);
    DUMP_VAR(p_Qm->p_QmRegs, fqd_bar);
    DUMP_VAR(p_Qm->p_QmRegs, fqd_ar);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_bare);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_bar);
    DUMP_VAR(p_Qm->p_QmRegs, pfdr_ar);
    DUMP_VAR(p_Qm->p_QmRegs, qcsp_bare);
    DUMP_VAR(p_Qm->p_QmRegs, qcsp_bar);
    DUMP_VAR(p_Qm->p_QmRegs, ci_sched_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, srcidr);
    DUMP_VAR(p_Qm->p_QmRegs, liodnr);
    DUMP_VAR(p_Qm->p_QmRegs, ci_rlm_cfg);
    DUMP_VAR(p_Qm->p_QmRegs, ci_rlm_avg);
    DUMP_VAR(p_Qm->p_QmRegs, err_isr);
    DUMP_VAR(p_Qm->p_QmRegs, err_ier);
    DUMP_VAR(p_Qm->p_QmRegs, err_isdr);
    DUMP_VAR(p_Qm->p_QmRegs, err_iir);
    DUMP_VAR(p_Qm->p_QmRegs, err_her);

    return E_OK;
}
#endif /* (defined(DEBUG_ERRORS) && ... */