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