1/* 2 * Copyright 2008-2012 Freescale Semiconductor Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * * Neither the name of Freescale Semiconductor nor the 12 * names of its contributors may be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * 16 * ALTERNATIVELY, this software may be distributed under the terms of the 17 * GNU General Public License ("GPL") as published by the Free Software 18 * Foundation, either version 2 of that License or (at your option) any 19 * later version. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34/****************************************************************************** 35 @File fm_port_im.c 36 37 @Description FM Port Independent-Mode ... 38*//***************************************************************************/ 39#include "std_ext.h" 40#include "string_ext.h" 41#include "error_ext.h" 42#include "memcpy_ext.h" 43#include "fm_muram_ext.h" 44 45#include "fm_port.h" 46 47 48#define TX_CONF_STATUS_UNSENT 0x1 49 50 51typedef enum e_TxConfType 52{ 53 e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ 54 ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ 55 ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ 56} e_TxConfType; 57 58 59static void ImException(t_Handle h_FmPort, uint32_t event) 60{ 61 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 62 63 ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) || 64 !FmIsMaster(p_FmPort->h_Fm)); 65 66 if (event & IM_EV_RX) 67 FmPortImRx(p_FmPort); 68 if ((event & IM_EV_BSY) && p_FmPort->f_Exception) 69 p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); 70} 71 72 73static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) 74{ 75 t_Error retVal = E_BUSY; 76 uint32_t bdStatus; 77 uint16_t savedStartBdId, confBdId; 78 79 ASSERT_COND(p_FmPort); 80 81 /* 82 if (confType==e_TX_CONF_TYPE_CHECK) 83 return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); 84 */ 85 86 confBdId = savedStartBdId = p_FmPort->im.currBdId; 87 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); 88 89 /* If R bit is set, we don't enter, or we break. 90 we run till we get to R, or complete the loop */ 91 while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) 92 { 93 if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ 94 BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); 95 96 /* case 1: R bit is 0 and Length is set -> confirm! */ 97 if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) 98 { 99 if (p_FmPort->im.f_TxConf) 100 { 101 if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) 102 p_FmPort->im.f_TxConf(p_FmPort->h_App, 103 BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), 104 TX_CONF_STATUS_UNSENT, 105 p_FmPort->im.p_BdShadow[confBdId]); 106 else 107 p_FmPort->im.f_TxConf(p_FmPort->h_App, 108 BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), 109 0, 110 p_FmPort->im.p_BdShadow[confBdId]); 111 } 112 } 113 /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ 114 115 confBdId = GetNextBdId(p_FmPort, confBdId); 116 if (confBdId == savedStartBdId) 117 retVal = E_OK; 118 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); 119 } 120 121 return retVal; 122} 123 124t_Error FmPortImEnable(t_FmPort *p_FmPort) 125{ 126 uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); 127 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); 128 return E_OK; 129} 130 131t_Error FmPortImDisable(t_FmPort *p_FmPort) 132{ 133 uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); 134 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); 135 return E_OK; 136} 137 138t_Error FmPortImRx(t_FmPort *p_FmPort) 139{ 140 t_Handle h_CurrUserPriv, h_NewUserPriv; 141 uint32_t bdStatus; 142 volatile uint8_t buffPos; 143 uint16_t length; 144 uint16_t errors; 145 uint8_t *p_CurData, *p_Data; 146 uint32_t flags; 147 148 ASSERT_COND(p_FmPort); 149 150 flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); 151 if (p_FmPort->lock) 152 { 153 XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); 154 return E_OK; 155 } 156 p_FmPort->lock = TRUE; 157 XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); 158 159 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); 160 161 while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ 162 { 163 if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) 164 { 165 p_FmPort->lock = FALSE; 166 RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); 167 } 168 169 if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) 170 p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; 171 172 p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); 173 h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; 174 length = (uint16_t)((bdStatus & BD_L) ? 175 ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): 176 (bdStatus & BD_LENGTH_MASK)); 177 p_FmPort->im.rxFrameAccumLength += length; 178 179 /* determine whether buffer is first, last, first and last (single */ 180 /* buffer frame) or middle (not first and not last) */ 181 buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? 182 ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : 183 ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); 184 185 if (bdStatus & BD_L) 186 { 187 p_FmPort->im.rxFrameAccumLength = 0; 188 p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; 189 } 190 191 BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); 192 193 BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); 194 195 errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); 196 p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; 197 198 p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); 199 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); 200 /* Pass the buffer if one of the conditions is true: 201 - There are no errors 202 - This is a part of a larger frame ( the application has already received some buffers ) */ 203 if ((buffPos != SINGLE_BUF) || !errors) 204 { 205 if (p_FmPort->im.f_RxStore(p_FmPort->h_App, 206 p_CurData, 207 length, 208 errors, 209 buffPos, 210 h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) 211 break; 212 } 213 else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, 214 p_CurData, 215 h_CurrUserPriv)) 216 { 217 p_FmPort->lock = FALSE; 218 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); 219 } 220 221 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); 222 } 223 p_FmPort->lock = FALSE; 224 return E_OK; 225} 226 227void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) 228{ 229 ASSERT_COND(p_FmPort); 230 231 SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 232 233 p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; 234 p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; 235 p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; 236 p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; 237 238 p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; 239 p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; 240 241 if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || 242 (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) 243 { 244 p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; 245 p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; 246 p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; 247 p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; 248 p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; 249 if (!p_FmPort->im.rxPool.f_PhysToVirt) 250 p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; 251 p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; 252 if (!p_FmPort->im.rxPool.f_VirtToPhys) 253 p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; 254 p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; 255 256 p_FmPort->im.mrblr = 0x8000; 257 while (p_FmPort->im.mrblr) 258 { 259 if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) 260 break; 261 p_FmPort->im.mrblr >>= 1; 262 } 263 if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) 264 DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); 265 p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; 266 p_FmPort->exceptions = DEFAULT_PORT_exception; 267 if (FmIsMaster(p_FmPort->h_Fm)) 268 p_FmPort->polling = FALSE; 269 else 270 p_FmPort->polling = TRUE; 271 p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; 272 } 273 else 274 { 275 p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; 276 277 p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; 278 } 279} 280 281t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) 282{ 283 if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && 284 (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && 285 (p_FmPort->portType != e_FM_PORT_TYPE_TX) && 286 (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) 287 RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); 288 289 if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || 290 (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) 291 { 292 if (!POWER_OF_2(p_FmPort->im.mrblr)) 293 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); 294 if (p_FmPort->im.mrblr < 256) 295 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); 296 if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) 297 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); 298 } 299 300 return E_OK; 301} 302 303t_Error FmPortImInit(t_FmPort *p_FmPort) 304{ 305 t_FmImBd *p_Bd=NULL; 306 t_Handle h_BufContext; 307 uint64_t tmpPhysBase; 308 uint16_t log2Num; 309 uint8_t *p_Data/*, *p_Tmp*/; 310 int i; 311 t_Error err; 312 uint16_t tmpReg16; 313 uint32_t tmpReg32; 314 315 ASSERT_COND(p_FmPort); 316 317 p_FmPort->im.p_FmPortImPram = 318 (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); 319 if (!p_FmPort->im.p_FmPortImPram) 320 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); 321 WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); 322 323 if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || 324 (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) 325 { 326 p_FmPort->im.p_BdRing = 327 (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), 328 p_FmPort->im.fwExtStructsMemId, 329 4); 330 if (!p_FmPort->im.p_BdRing) 331 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); 332 IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); 333 334 p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); 335 if (!p_FmPort->im.p_BdShadow) 336 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); 337 memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); 338 339 /* Initialize the Rx-BD ring */ 340 for (i=0; i<p_FmPort->im.bdRingSize; i++) 341 { 342 p_Bd = BD_GET(i); 343 BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); 344 345 if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) 346 RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); 347 BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); 348 p_FmPort->im.p_BdShadow[i] = h_BufContext; 349 } 350 351 if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || 352 (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) 353 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); 354 else 355 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); 356 357 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, 358 (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - 359 p_FmPort->fmMuramPhysBaseAddr + 0x20)); 360 361 LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); 362 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); 363 364 /* Initialize Rx QD */ 365 tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); 366 SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); 367 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); 368 369 /* Update the IM PRAM address in the BMI */ 370 WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, 371 (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - 372 p_FmPort->fmMuramPhysBaseAddr)); 373 if (!p_FmPort->polling || p_FmPort->exceptions) 374 { 375 /* Allocate, configure and register interrupts */ 376 err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); 377 if (err) 378 RETURN_ERROR(MAJOR, err, NO_MSG); 379 380 ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); 381 tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); 382 tmpReg32 = 0; 383 384 if (p_FmPort->exceptions & IM_EV_BSY) 385 { 386 tmpReg16 |= IM_RXQD_BSYINTM; 387 tmpReg32 |= IM_EV_BSY; 388 } 389 if (!p_FmPort->polling) 390 { 391 tmpReg16 |= IM_RXQD_RXFINTM; 392 tmpReg32 |= IM_EV_RX; 393 } 394 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); 395 396 FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); 397 398 FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); 399 } 400 else 401 p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; 402 } 403 else 404 { 405 p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); 406 if (!p_FmPort->im.p_BdRing) 407 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); 408 IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); 409 410 p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); 411 if (!p_FmPort->im.p_BdShadow) 412 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); 413 memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); 414 p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; 415 416 if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || 417 (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) 418 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); 419 else 420 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); 421 422 WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, 423 (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - 424 p_FmPort->fmMuramPhysBaseAddr + 0x40)); 425 426 /* Initialize Tx QD */ 427 tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); 428 SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); 429 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); 430 431 /* Update the IM PRAM address in the BMI */ 432 WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, 433 (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - 434 p_FmPort->fmMuramPhysBaseAddr)); 435 } 436 437 438 return E_OK; 439} 440 441void FmPortImFree(t_FmPort *p_FmPort) 442{ 443 uint32_t bdStatus; 444 uint8_t *p_CurData; 445 446 ASSERT_COND(p_FmPort); 447 ASSERT_COND(p_FmPort->im.p_FmPortImPram); 448 449 if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || 450 (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) 451 { 452 if (!p_FmPort->polling || p_FmPort->exceptions) 453 { 454 /* Deallocate and unregister interrupts */ 455 FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); 456 457 FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); 458 459 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); 460 461 FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); 462 } 463 /* Try first clean what has received */ 464 FmPortImRx(p_FmPort); 465 466 /* Now, get rid of the the empty buffer! */ 467 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); 468 469 while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ 470 { 471 p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); 472 473 BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); 474 BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); 475 476 p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, 477 p_CurData, 478 p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); 479 480 p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); 481 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); 482 } 483 } 484 else 485 TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); 486 487 FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); 488 489 if (p_FmPort->im.p_BdShadow) 490 XX_Free(p_FmPort->im.p_BdShadow); 491 492 if (p_FmPort->im.p_BdRing) 493 XX_FreeSmart(p_FmPort->im.p_BdRing); 494} 495 496 497t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) 498{ 499 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 500 501 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 502 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 503 SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 504 505 p_FmPort->im.mrblr = newVal; 506 507 return E_OK; 508} 509 510t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) 511{ 512 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 513 514 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 515 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 516 SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 517 518 p_FmPort->im.bdRingSize = newVal; 519 520 return E_OK; 521} 522 523t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) 524{ 525 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 526 527 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 528 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 529 SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 530 531 p_FmPort->im.bdRingSize = newVal; 532 533 return E_OK; 534} 535 536t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, 537 uint8_t memId, 538 uint32_t memAttributes) 539{ 540 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 541 542 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 543 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 544 SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 545 546 p_FmPort->im.fwExtStructsMemId = memId; 547 p_FmPort->im.fwExtStructsMemAttr = memAttributes; 548 549 return E_OK; 550} 551 552t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) 553{ 554 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 555 556 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 557 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 558 SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 559 560 if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) 561 RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); 562 563 if (!FmIsMaster(p_FmPort->h_Fm)) 564 RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" 565 "in guest-partitions, IM is always in polling!")); 566 567 p_FmPort->polling = TRUE; 568 569 return E_OK; 570} 571 572t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) 573{ 574 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 575 t_Error err; 576 uint16_t tmpReg16; 577 uint32_t tmpReg32; 578 579 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 580 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 581 SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 582 583 if (exception == e_FM_PORT_EXCEPTION_IM_BUSY) 584 { 585 if (enable) 586 { 587 p_FmPort->exceptions |= IM_EV_BSY; 588 if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) 589 { 590 /* Allocate, configure and register interrupts */ 591 err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); 592 if (err) 593 RETURN_ERROR(MAJOR, err, NO_MSG); 594 ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); 595 596 FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); 597 tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); 598 tmpReg32 = IM_EV_BSY; 599 } 600 else 601 { 602 tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); 603 tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; 604 } 605 606 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); 607 FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); 608 } 609 else 610 { 611 p_FmPort->exceptions &= ~IM_EV_BSY; 612 if (!p_FmPort->exceptions && p_FmPort->polling) 613 { 614 FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); 615 FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); 616 FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); 617 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); 618 p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; 619 } 620 else 621 { 622 tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); 623 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); 624 tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; 625 FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); 626 } 627 } 628 } 629 else 630 RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); 631 632 return E_OK; 633} 634 635t_Error FM_PORT_ImTx( t_Handle h_FmPort, 636 uint8_t *p_Data, 637 uint16_t length, 638 bool lastBuffer, 639 t_Handle h_BufContext) 640{ 641 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 642 uint16_t nextBdId; 643 uint32_t bdStatus, nextBdStatus; 644 bool firstBuffer; 645 646 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 647 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 648 SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 649 650 bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); 651 nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); 652 nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); 653 654 if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) 655 { 656 /* Confirm the current BD - BD is available */ 657 if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) 658 p_FmPort->im.f_TxConf (p_FmPort->h_App, 659 BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), 660 0, 661 p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); 662 663 bdStatus = length; 664 665 /* if this is the first BD of a frame */ 666 if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) 667 { 668 firstBuffer = TRUE; 669 p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); 670 671 if (!lastBuffer) 672 p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; 673 } 674 else 675 firstBuffer = FALSE; 676 677 BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); 678 p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; 679 680 /* deal with last */ 681 if (lastBuffer) 682 { 683 /* if single buffer frame */ 684 if (firstBuffer) 685 BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); 686 else 687 { 688 /* Set the last BD of the frame */ 689 BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); 690 /* Set the first BD of the frame */ 691 BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); 692 p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; 693 } 694 WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); 695 } 696 else if (!firstBuffer) /* mid frame buffer */ 697 BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); 698 699 p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); 700 } 701 else 702 { 703 /* Discard current frame. Return error. */ 704 if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) 705 { 706 /* Error: No free BD */ 707 /* Response: Discard current frame. Return error. */ 708 uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; 709 710 ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); 711 712 /* Since firstInFrame is not NULL, one buffer at least has already been 713 inserted into the BD ring. Using do-while covers the situation of a 714 frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented 715 prior to testing whether or not it's equal to TxBd). */ 716 do 717 { 718 BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); 719 /* Advance BD pointer */ 720 cleanBdId = GetNextBdId(p_FmPort, cleanBdId); 721 } while (cleanBdId != p_FmPort->im.currBdId); 722 723 p_FmPort->im.currBdId = cleanBdId; 724 p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; 725 } 726 727 return ERROR_CODE(E_FULL); 728 } 729 730 return E_OK; 731} 732 733void FM_PORT_ImTxConf(t_Handle h_FmPort) 734{ 735 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 736 737 SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); 738 SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); 739 SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 740 741 TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); 742} 743 744t_Error FM_PORT_ImRx(t_Handle h_FmPort) 745{ 746 t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; 747 748 SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); 749 SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); 750 SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); 751 752 return FmPortImRx(p_FmPort); 753} 754