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 
51 typedef 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 
59 static 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 
73 static 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 
124 t_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 
131 t_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 
138 t_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 
227 void 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 
281 t_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 
303 t_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 
441 void 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 
497 t_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 
510 t_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 
523 t_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 
536 t_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 
552 t_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 
572 t_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 
635 t_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 
733 void 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 
744 t_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