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