/* * Copyright 2008-2012 Freescale Semiconductor Inc. * * 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. * * * ALTERNATIVELY, this software may be distributed under the terms of the * GNU General Public License ("GPL") as published by the Free Software * Foundation, either version 2 of that License or (at your option) any * later version. * * 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 fm_port_im.c @Description FM Port Independent-Mode ... *//***************************************************************************/ #include "std_ext.h" #include "string_ext.h" #include "error_ext.h" #include "memcpy_ext.h" #include "fm_muram_ext.h" #include "fm_port.h" #define TX_CONF_STATUS_UNSENT 0x1 typedef enum e_TxConfType { e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ } e_TxConfType; static void ImException(t_Handle h_FmPort, uint32_t event) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) || !FmIsMaster(p_FmPort->h_Fm)); if (event & IM_EV_RX) FmPortImRx(p_FmPort); if ((event & IM_EV_BSY) && p_FmPort->f_Exception) p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); } static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) { t_Error retVal = E_BUSY; uint32_t bdStatus; uint16_t savedStartBdId, confBdId; ASSERT_COND(p_FmPort); /* if (confType==e_TX_CONF_TYPE_CHECK) return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); */ confBdId = savedStartBdId = p_FmPort->im.currBdId; bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); /* If R bit is set, we don't enter, or we break. we run till we get to R, or complete the loop */ while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) { if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); /* case 1: R bit is 0 and Length is set -> confirm! */ if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) { if (p_FmPort->im.f_TxConf) { if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) p_FmPort->im.f_TxConf(p_FmPort->h_App, BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), TX_CONF_STATUS_UNSENT, p_FmPort->im.p_BdShadow[confBdId]); else p_FmPort->im.f_TxConf(p_FmPort->h_App, BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), 0, p_FmPort->im.p_BdShadow[confBdId]); } } /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ confBdId = GetNextBdId(p_FmPort, confBdId); if (confBdId == savedStartBdId) retVal = E_OK; bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); } return retVal; } t_Error FmPortImEnable(t_FmPort *p_FmPort) { uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); return E_OK; } t_Error FmPortImDisable(t_FmPort *p_FmPort) { uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); return E_OK; } t_Error FmPortImRx(t_FmPort *p_FmPort) { t_Handle h_CurrUserPriv, h_NewUserPriv; uint32_t bdStatus; volatile uint8_t buffPos; uint16_t length; uint16_t errors; uint8_t *p_CurData, *p_Data; uint32_t flags; ASSERT_COND(p_FmPort); flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); if (p_FmPort->lock) { XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); return E_OK; } p_FmPort->lock = TRUE; XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ { if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) { p_FmPort->lock = FALSE; RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); } if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; length = (uint16_t)((bdStatus & BD_L) ? ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): (bdStatus & BD_LENGTH_MASK)); p_FmPort->im.rxFrameAccumLength += length; /* determine whether buffer is first, last, first and last (single */ /* buffer frame) or middle (not first and not last) */ buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); if (bdStatus & BD_L) { p_FmPort->im.rxFrameAccumLength = 0; p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; } BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); /* Pass the buffer if one of the conditions is true: - There are no errors - This is a part of a larger frame ( the application has already received some buffers ) */ if ((buffPos != SINGLE_BUF) || !errors) { if (p_FmPort->im.f_RxStore(p_FmPort->h_App, p_CurData, length, errors, buffPos, h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) break; } else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, p_CurData, h_CurrUserPriv)) { p_FmPort->lock = FALSE; RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); } bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); } p_FmPort->lock = FALSE; return E_OK; } void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) { ASSERT_COND(p_FmPort); SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) { p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; if (!p_FmPort->im.rxPool.f_PhysToVirt) p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; if (!p_FmPort->im.rxPool.f_VirtToPhys) p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; p_FmPort->im.mrblr = 0x8000; while (p_FmPort->im.mrblr) { if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) break; p_FmPort->im.mrblr >>= 1; } if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; p_FmPort->exceptions = DEFAULT_PORT_exception; if (FmIsMaster(p_FmPort->h_Fm)) p_FmPort->polling = FALSE; else p_FmPort->polling = TRUE; p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; } else { p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; } } t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) { if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_TX) && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) { if (!POWER_OF_2(p_FmPort->im.mrblr)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); if (p_FmPort->im.mrblr < 256) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); } return E_OK; } t_Error FmPortImInit(t_FmPort *p_FmPort) { t_FmImBd *p_Bd=NULL; t_Handle h_BufContext; uint64_t tmpPhysBase; uint16_t log2Num; uint8_t *p_Data/*, *p_Tmp*/; int i; t_Error err; uint16_t tmpReg16; uint32_t tmpReg32; ASSERT_COND(p_FmPort); p_FmPort->im.p_FmPortImPram = (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); if (!p_FmPort->im.p_FmPortImPram) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) { p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); if (!p_FmPort->im.p_BdRing) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); if (!p_FmPort->im.p_BdShadow) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); /* Initialize the Rx-BD ring */ for (i=0; iim.bdRingSize; i++) { p_Bd = BD_GET(i); BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); p_FmPort->im.p_BdShadow[i] = h_BufContext; } if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); else WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - p_FmPort->fmMuramPhysBaseAddr + 0x20)); LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); /* Initialize Rx QD */ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); /* Update the IM PRAM address in the BMI */ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - p_FmPort->fmMuramPhysBaseAddr)); if (!p_FmPort->polling || p_FmPort->exceptions) { /* Allocate, configure and register interrupts */ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); if (err) RETURN_ERROR(MAJOR, err, NO_MSG); ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); tmpReg32 = 0; if (p_FmPort->exceptions & IM_EV_BSY) { tmpReg16 |= IM_RXQD_BSYINTM; tmpReg32 |= IM_EV_BSY; } if (!p_FmPort->polling) { tmpReg16 |= IM_RXQD_RXFINTM; tmpReg32 |= IM_EV_RX; } WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); } else p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; } else { p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); if (!p_FmPort->im.p_BdRing) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); if (!p_FmPort->im.p_BdShadow) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); else WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - p_FmPort->fmMuramPhysBaseAddr + 0x40)); /* Initialize Tx QD */ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); /* Update the IM PRAM address in the BMI */ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - p_FmPort->fmMuramPhysBaseAddr)); } return E_OK; } void FmPortImFree(t_FmPort *p_FmPort) { uint32_t bdStatus; uint8_t *p_CurData; ASSERT_COND(p_FmPort); ASSERT_COND(p_FmPort->im.p_FmPortImPram); if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) { if (!p_FmPort->polling || p_FmPort->exceptions) { /* Deallocate and unregister interrupts */ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); } /* Try first clean what has received */ FmPortImRx(p_FmPort); /* Now, get rid of the the empty buffer! */ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ { p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, p_CurData, p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); } } else TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); if (p_FmPort->im.p_BdShadow) XX_Free(p_FmPort->im.p_BdShadow); if (p_FmPort->im.p_BdRing) XX_FreeSmart(p_FmPort->im.p_BdRing); } t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); p_FmPort->im.mrblr = newVal; return E_OK; } t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); p_FmPort->im.bdRingSize = newVal; return E_OK; } t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); p_FmPort->im.bdRingSize = newVal; return E_OK; } t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, uint8_t memId, uint32_t memAttributes) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); p_FmPort->im.fwExtStructsMemId = memId; p_FmPort->im.fwExtStructsMemAttr = memAttributes; return E_OK; } t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); if (!FmIsMaster(p_FmPort->h_Fm)) RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" "in guest-partitions, IM is always in polling!")); p_FmPort->polling = TRUE; return E_OK; } t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; t_Error err; uint16_t tmpReg16; uint32_t tmpReg32; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); if (exception == e_FM_PORT_EXCEPTION_IM_BUSY) { if (enable) { p_FmPort->exceptions |= IM_EV_BSY; if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) { /* Allocate, configure and register interrupts */ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); if (err) RETURN_ERROR(MAJOR, err, NO_MSG); ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); tmpReg32 = IM_EV_BSY; } else { tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; } WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); } else { p_FmPort->exceptions &= ~IM_EV_BSY; if (!p_FmPort->exceptions && p_FmPort->polling) { FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; } else { tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); } } } else RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); return E_OK; } t_Error FM_PORT_ImTx( t_Handle h_FmPort, uint8_t *p_Data, uint16_t length, bool lastBuffer, t_Handle h_BufContext) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; uint16_t nextBdId; uint32_t bdStatus, nextBdStatus; bool firstBuffer; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) { /* Confirm the current BD - BD is available */ if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) p_FmPort->im.f_TxConf (p_FmPort->h_App, BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), 0, p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); bdStatus = length; /* if this is the first BD of a frame */ if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) { firstBuffer = TRUE; p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); if (!lastBuffer) p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; } else firstBuffer = FALSE; BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; /* deal with last */ if (lastBuffer) { /* if single buffer frame */ if (firstBuffer) BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); else { /* Set the last BD of the frame */ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); /* Set the first BD of the frame */ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; } WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); } else if (!firstBuffer) /* mid frame buffer */ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); } else { /* Discard current frame. Return error. */ if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) { /* Error: No free BD */ /* Response: Discard current frame. Return error. */ uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); /* Since firstInFrame is not NULL, one buffer at least has already been inserted into the BD ring. Using do-while covers the situation of a frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented prior to testing whether or not it's equal to TxBd). */ do { BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); /* Advance BD pointer */ cleanBdId = GetNextBdId(p_FmPort, cleanBdId); } while (cleanBdId != p_FmPort->im.currBdId); p_FmPort->im.currBdId = cleanBdId; p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; } return ERROR_CODE(E_FULL); } return E_OK; } void FM_PORT_ImTxConf(t_Handle h_FmPort) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); } t_Error FM_PORT_ImRx(t_Handle h_FmPort) { t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); return FmPortImRx(p_FmPort); }