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