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_plcr.c
35
36 @Description   FM PCD POLICER...
37*//***************************************************************************/
38#include "std_ext.h"
39#include "error_ext.h"
40#include "string_ext.h"
41#include "debug_ext.h"
42#include "net_ext.h"
43#include "fm_ext.h"
44
45#include "fm_common.h"
46#include "fm_pcd.h"
47#include "fm_hc.h"
48#include "fm_pcd_ipc.h"
49
50
51static bool FmPcdPlcrIsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId)
52{
53    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
54    uint16_t        i;
55
56    SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE);
57
58    for(i=0;i<p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;i++)
59        if(p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId)
60            return TRUE;
61    return FALSE;
62}
63
64static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction)
65{
66    uint32_t    nia;
67    uint16_t    absoluteProfileId = (uint16_t)(PTR_TO_UINT(p_NextEngineParams->h_Profile)-1);
68    uint8_t     relativeSchemeId, physicatSchemeId;
69
70    nia = FM_PCD_PLCR_NIA_VALID;
71
72    switch (nextEngine)
73    {
74        case e_FM_PCD_DONE :
75            switch (p_NextEngineParams->action)
76            {
77                case e_FM_PCD_DROP_FRAME :
78                    nia |= (NIA_ENG_BMI | NIA_BMI_AC_DISCARD);
79                    break;
80                case e_FM_PCD_ENQ_FRAME:
81                    nia |= (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME);
82                    break;
83                default:
84                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
85            }
86            break;
87        case e_FM_PCD_KG:
88            physicatSchemeId = (uint8_t)(PTR_TO_UINT(p_NextEngineParams->h_DirectScheme)-1);
89            relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicatSchemeId);
90            if(relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES)
91                RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG);
92            if (!FmPcdKgIsSchemeValidSw(p_FmPcd, relativeSchemeId))
93                 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme."));
94            if(!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId))
95                RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct."));
96            nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicatSchemeId;
97            break;
98        case e_FM_PCD_PLCR:
99             if(!FmPcdPlcrIsProfileShared(p_FmPcd, absoluteProfileId))
100               RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile"));
101             if(!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId))
102               RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile "));
103            nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId;
104            break;
105        default:
106            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
107    }
108
109    *nextAction =  nia;
110
111    return E_OK;
112}
113
114static uint32_t FPP_Function(uint32_t fpp)
115{
116    if(fpp > 15)
117        return 15 - (0x1f - fpp);
118    else
119        return 16 + fpp;
120}
121
122static void GetInfoRateReg(e_FmPcdPlcrRateMode rateMode,
123                                uint32_t rate,
124                                uint64_t tsuInTenthNano,
125                                uint32_t fppShift,
126                                uint64_t *p_Integer,
127                                uint64_t *p_Fraction)
128{
129    uint64_t tmp, div;
130
131    if(rateMode == e_FM_PCD_PLCR_BYTE_MODE)
132    {
133        /* now we calculate the initial integer for the bigger rate */
134        /* from Kbps to Bytes/TSU */
135        tmp = (uint64_t)rate;
136        tmp *= 1000; /* kb --> b */
137        tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
138
139        div = 1000000000;   /* nano */
140        div *= 10;          /* 10 nano */
141        div *= 8;           /* bit to byte */
142    }
143    else
144    {
145        /* now we calculate the initial integer for the bigger rate */
146        /* from Kbps to Bytes/TSU */
147        tmp = (uint64_t)rate;
148        tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */
149
150        div = 1000000000;   /* nano */
151        div *= 10;          /* 10 nano */
152    }
153    *p_Integer = (tmp<<fppShift)/div;
154
155    /* for calculating the fraction, we will recalculate cir and deduct the integer.
156     * For precision, we will multiply by 2^16. we do not divid back, since we write
157     * this value as fraction - see spec.
158     */
159    *p_Fraction = (((tmp<<fppShift)<<16) - ((*p_Integer<<16)*div))/div;
160}
161
162/* .......... */
163
164static void calcRates(t_Handle h_FmPcd, t_FmPcdPlcrNonPassthroughAlgParams *p_NonPassthroughAlgParam,
165                        uint32_t *cir, uint32_t *cbs, uint32_t *pir_eir, uint32_t *pbs_ebs, uint32_t *fpp)
166{
167    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
168    uint64_t    integer, fraction;
169    uint32_t    temp, tsuInTenthNanos, bitFor1Micro;
170    uint8_t     fppShift=0;
171
172    bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm);  /* TimeStamp per nano seconds units */
173    /* we want the tsu to count 10 nano for better precision normally tsu is 3.9 nano, now we will get 39 */
174    tsuInTenthNanos = (uint32_t)(1000*10/(1<<bitFor1Micro));
175
176    /* we choose the faster rate to calibrate fpp */
177    if (p_NonPassthroughAlgParam->comittedInfoRate > p_NonPassthroughAlgParam->peakOrAccessiveInfoRate)
178        GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->comittedInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
179    else
180        GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrAccessiveInfoRate, tsuInTenthNanos, 0, &integer, &fraction);
181
182
183    /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and
184     * the LSB bits are for the fraction */
185    temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF);
186    /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll
187     * take max fpp=31.
188     * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is
189     * limited by the 10G physical port.
190     */
191    if(temp != 0)
192    {
193        /* count zeroes left of the higher used bit (in order to shift the value such that
194         * unused bits may be used for fraction).
195         */
196        while ((temp & 0x80000000) == 0)
197        {
198            temp = temp << 1;
199            fppShift++;
200        }
201        if(fppShift > 15)
202        {
203            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small"));
204            return;
205        }
206    }
207    else
208    {
209        temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */
210        if(!temp)
211            /* integer and fraction are 0, we set fpp to its max val */
212            fppShift = 31;
213        else
214        {
215            /* integer was 0 but fraction is not. fpp is 16 for the integer,
216             * + all left zeroes of the fraction. */
217            fppShift=16;
218            /* count zeroes left of the higher used bit (in order to shift the value such that
219             * unused bits may be used for fraction).
220             */
221            while ((temp & 0x8000) == 0)
222            {
223                temp = temp << 1;
224                fppShift++;
225            }
226        }
227    }
228
229    /*
230     * This means that the FM TS register will now be used so that 'count' bits are for
231     * fraction and the rest for integer */
232    /* now we re-calculate cir */
233    GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->comittedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
234    *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
235    GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrAccessiveInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction);
236    *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF));
237
238    *cbs     =  p_NonPassthroughAlgParam->comittedBurstSize;
239    *pbs_ebs =  p_NonPassthroughAlgParam->peakOrAccessiveBurstSize;
240
241    /* get fpp as it should be written to reg.*/
242    *fpp = FPP_Function(fppShift);
243
244}
245
246static void WritePar(t_FmPcd *p_FmPcd, uint32_t par)
247{
248    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs    = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
249
250    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
251    WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par);
252
253    while(GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ;
254
255}
256
257/*********************************************/
258/*............Policer Exception..............*/
259/*********************************************/
260static void PcdPlcrException(t_Handle h_FmPcd)
261{
262    t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd;
263    uint32_t event, mask, force;
264
265    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
266    event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr);
267    mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier);
268
269    event &= mask;
270
271    /* clear the forced events */
272    force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr);
273    if(force & event)
274        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event);
275
276
277    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event);
278
279    if(event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE)
280        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE);
281    if(event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)
282        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE);
283
284}
285
286/* ..... */
287
288static void PcdPlcrErrorException(t_Handle h_FmPcd)
289{
290    t_FmPcd             *p_FmPcd = (t_FmPcd *)h_FmPcd;
291    uint32_t            event, force, captureReg, mask;
292
293    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
294    event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr);
295    mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier);
296
297    event &= mask;
298
299    /* clear the forced events */
300    force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr);
301    if(force & event)
302        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event);
303
304    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event);
305
306    if(event & FM_PCD_PLCR_DOUBLE_ECC)
307        p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC);
308    if(event & FM_PCD_PLCR_INIT_ENTRY_ERROR)
309    {
310        captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr);
311        /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP);
312        p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK);
313        p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ;
314        p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/
315        p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK));
316        WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP);
317    }
318}
319
320void FmPcdPlcrUpatePointedOwner(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool add)
321{
322    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
323
324   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
325
326    if(add)
327        p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners++;
328    else
329        p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners--;
330}
331
332uint32_t FmPcdPlcrGetPointedOwners(t_Handle h_FmPcd, uint16_t absoluteProfileId)
333{
334    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
335
336   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
337
338    return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].pointedOwners;
339}
340uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId)
341{
342    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
343
344   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
345
346    return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction;
347}
348
349t_Error  FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles)
350{
351    t_FmPcd                     *p_FmPcd = (t_FmPcd*)h_FmPcd;
352    t_FmPcdIpcPlcrAllocParams   ipcPlcrParams;
353    t_Error                     err = E_OK;
354    uint16_t                    base;
355    uint16_t                    swPortIndex = 0;
356    t_FmPcdIpcMsg               msg;
357    uint32_t                    replyLength;
358    t_FmPcdIpcReply             reply;
359
360    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
361
362    if(!numOfProfiles)
363        return E_OK;
364
365    memset(&ipcPlcrParams, 0, sizeof(ipcPlcrParams));
366
367    if(p_FmPcd->guestId != NCSW_MASTER_ID)
368    {
369        /* Alloc resources using IPC messaging */
370        memset(&reply, 0, sizeof(reply));
371        memset(&msg, 0, sizeof(msg));
372        ipcPlcrParams.num = numOfProfiles;
373        ipcPlcrParams.hardwarePortId = hardwarePortId;
374        msg.msgId = FM_PCD_ALLOC_PROFILES;
375        memcpy(msg.msgBody, &ipcPlcrParams, sizeof(ipcPlcrParams));
376        replyLength = sizeof(uint32_t) + sizeof(uint16_t);
377        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
378                                     (uint8_t*)&msg,
379                                     sizeof(msg.msgId) +sizeof(ipcPlcrParams),
380                                     (uint8_t*)&reply,
381                                     &replyLength,
382                                     NULL,
383                                     NULL)) != E_OK)
384            RETURN_ERROR(MAJOR, err,NO_MSG);
385        if (replyLength != sizeof(uint32_t) + sizeof(uint16_t))
386            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
387        if((t_Error)reply.error != E_OK)
388            RETURN_ERROR(MAJOR, (t_Error)reply.error, ("PLCR profiles allocation failed"));
389
390        memcpy((uint8_t*)&base, reply.replyBody, sizeof(uint16_t));
391    }
392    else /* master */
393    {
394        err = PlcrAllocProfiles(p_FmPcd, hardwarePortId, numOfProfiles, &base);
395        if(err)
396            RETURN_ERROR(MAJOR, err,NO_MSG);
397    }
398    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
399
400    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles;
401    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = base;
402
403    return E_OK;
404}
405
406t_Error  FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
407{
408    t_FmPcd                     *p_FmPcd = (t_FmPcd*)h_FmPcd;
409    t_FmPcdIpcPlcrAllocParams   ipcPlcrParams;
410    t_Error                     err = E_OK;
411    uint16_t                    swPortIndex = 0;
412    t_FmPcdIpcMsg               msg;
413    uint32_t                    replyLength;
414    t_FmPcdIpcReply             reply;
415
416    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
417
418    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
419
420    if(p_FmPcd->guestId != NCSW_MASTER_ID)
421    {
422        /* Alloc resources using IPC messaging */
423        memset(&reply, 0, sizeof(reply));
424        memset(&msg, 0, sizeof(msg));
425        ipcPlcrParams.num = p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles;
426        ipcPlcrParams.hardwarePortId = hardwarePortId;
427        ipcPlcrParams.plcrProfilesBase = p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
428        msg.msgId = FM_PCD_FREE_PROFILES;
429        memcpy(msg.msgBody, &ipcPlcrParams, sizeof(ipcPlcrParams));
430        replyLength = sizeof(uint32_t);
431        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
432                                     (uint8_t*)&msg,
433                                     sizeof(msg.msgId) +sizeof(ipcPlcrParams),
434                                     (uint8_t*)&reply,
435                                     &replyLength,
436                                     NULL,
437                                     NULL)) != E_OK)
438            RETURN_ERROR(MAJOR, err,NO_MSG);
439        if (replyLength != sizeof(uint32_t))
440            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
441        if ((t_Error)reply.error != E_OK)
442            RETURN_ERROR(MINOR, (t_Error)reply.error, ("PLCR Free Profiles failed"));
443    }
444    else /* master */
445    {
446        err = PlcrFreeProfiles(p_FmPcd, hardwarePortId, p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles, p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase);
447        if(err)
448            RETURN_ERROR(MAJOR, err,NO_MSG);
449    }
450    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0;
451    p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0;
452
453    return E_OK;
454}
455
456bool    FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId)
457{
458    t_FmPcd         *p_FmPcd            = (t_FmPcd*)h_FmPcd;
459    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
460
461    return p_FmPcdPlcr->profiles[absoluteProfileId].valid;
462}
463
464t_Error  PlcrAllocProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles, uint16_t *p_Base)
465{
466    t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
467    uint32_t        profilesFound, log2Num, tmpReg32;
468    uint32_t        intFlags;
469    uint16_t        first, i;
470
471    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
472
473    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
474    if(!numOfProfiles)
475        return E_OK;
476
477    ASSERT_COND(hardwarePortId);
478
479    if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
480        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
481
482    if (!POWER_OF_2(numOfProfiles))
483        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2."));
484
485    intFlags = FmPcdLock(p_FmPcd);
486
487    if(GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V)
488    {
489        FmPcdUnlock(p_FmPcd, intFlags);
490        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("The requesting port has already an allocated profiles window."));
491    }
492
493    first = 0;
494    profilesFound = 0;
495    for(i=0;i<FM_PCD_PLCR_NUM_ENTRIES;)
496    {
497        if(!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
498        {
499            profilesFound++;
500            i++;
501            if(profilesFound == numOfProfiles)
502                break;
503        }
504        else
505        {
506            profilesFound = 0;
507            /* advance i to the next aligned address */
508            first = i = (uint8_t)(first + numOfProfiles);
509        }
510    }
511    if(profilesFound == numOfProfiles)
512    {
513        for(i = first; i<first + numOfProfiles; i++)
514        {
515            p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE;
516            p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId;
517        }
518    }
519    else
520    {
521        FmPcdUnlock(p_FmPcd, intFlags);
522        RETURN_ERROR(MINOR, E_FULL, ("No profiles."));
523    }
524
525    /**********************FMPL_PMRx******************/
526    LOG2((uint64_t)numOfProfiles, log2Num);
527    tmpReg32 = first;
528    tmpReg32 |= log2Num << 16;
529    tmpReg32 |= FM_PCD_PLCR_PMR_V;
530    WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32);
531
532    *p_Base = first;
533
534    FmPcdUnlock(p_FmPcd, intFlags);
535
536    return E_OK;
537}
538
539t_Error  PlcrAllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
540{
541    uint32_t        profilesFound;
542    uint16_t        i, k=0;
543
544    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
545
546    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
547    if(!numOfProfiles)
548        return E_OK;
549
550    if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES)
551        RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big."));
552
553    profilesFound = 0;
554    for(i=0;i<FM_PCD_PLCR_NUM_ENTRIES; i++)
555    {
556        if(!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated)
557        {
558            profilesFound++;
559            profilesIds[k] = i;
560            k++;
561            if(profilesFound == numOfProfiles)
562                break;
563        }
564    }
565    if(profilesFound != numOfProfiles)
566        RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG);
567    for(i = 0;i<k;i++)
568    {
569        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE;
570        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0;
571    }
572
573    return E_OK;
574}
575
576t_Error  PlcrFreeProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles, uint16_t base)
577{
578    t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
579    uint16_t        i;
580
581    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
582    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
583
584    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
585    ASSERT_COND(IN_RANGE(1, hardwarePortId, 63));
586    WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0);
587
588    for(i = base; i<base+numOfProfiles;i++)
589    {
590        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId);
591        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated);
592
593        p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE;
594        p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = 0;
595    }
596
597    return E_OK;
598}
599
600void  PlcrFreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds)
601{
602    uint16_t        i;
603
604    SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE);
605
606    ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm));
607    for(i=0;i<numOfProfiles; i++)
608    {
609        ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated);
610        p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE;
611    }
612}
613
614void PlcrEnable(t_FmPcd *p_FmPcd)
615{
616    t_FmPcdPlcrRegs             *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
617
618    WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN);
619}
620
621void PlcrDisable(t_FmPcd *p_FmPcd)
622{
623    t_FmPcdPlcrRegs             *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
624
625    WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN);
626}
627
628t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable)
629{
630   t_FmPcd  *p_FmPcd = (t_FmPcd*)h_FmPcd;
631   uint32_t tmpReg32;
632
633    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
634    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
635    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
636
637    if(!FmIsMaster(p_FmPcd->h_Fm))
638        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!"));
639
640    tmpReg32 =  GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr);
641    if(enable)
642        tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
643    else
644        tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN;
645
646    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32);
647    return E_OK;
648}
649
650t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable)
651{
652   t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
653
654    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
655    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
656    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
657
658    if(!FmIsMaster(p_FmPcd->h_Fm))
659        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!"));
660
661    p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable;
662
663    return E_OK;
664}
665
666
667t_Error FmPcdPlcrBuildProfile(t_Handle h_FmPcd, t_FmPcdPlcrProfileParams *p_Profile, t_FmPcdPlcrInterModuleProfileRegs *p_PlcrRegs)
668{
669
670    t_FmPcd         *p_FmPcd            = (t_FmPcd*)h_FmPcd;
671    t_Error         err = E_OK;
672    uint32_t        pemode, gnia, ynia, rnia;
673
674/* Set G, Y, R Nia */
675    err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnGreen,  &(p_Profile->paramsOnGreen), &gnia);
676    if(err)
677        RETURN_ERROR(MAJOR, err, NO_MSG);
678    err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnYellow, &(p_Profile->paramsOnYellow), &ynia);
679    if(err)
680        RETURN_ERROR(MAJOR, err, NO_MSG);
681    err = SetProfileNia(p_FmPcd, p_Profile->nextEngineOnRed,    &(p_Profile->paramsOnRed), &rnia);
682   if(err)
683        RETURN_ERROR(MAJOR, err, NO_MSG);
684
685
686/* Mode fmpl_pemode */
687    pemode = FM_PCD_PLCR_PEMODE_PI;
688
689    switch (p_Profile->algSelection)
690    {
691        case    e_FM_PCD_PLCR_PASS_THROUGH:
692            p_PlcrRegs->fmpl_pecir         = 0;
693            p_PlcrRegs->fmpl_pecbs         = 0;
694            p_PlcrRegs->fmpl_pepepir_eir   = 0;
695            p_PlcrRegs->fmpl_pepbs_ebs     = 0;
696            p_PlcrRegs->fmpl_pelts         = 0;
697            p_PlcrRegs->fmpl_pects         = 0;
698            p_PlcrRegs->fmpl_pepts_ets     = 0;
699            pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK;
700            switch (p_Profile->colorMode)
701            {
702                case    e_FM_PCD_PLCR_COLOR_BLIND:
703                    pemode |= FM_PCD_PLCR_PEMODE_CBLND;
704                    switch (p_Profile->color.dfltColor)
705                    {
706                        case e_FM_PCD_PLCR_GREEN:
707                            pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK;
708                            break;
709                        case e_FM_PCD_PLCR_YELLOW:
710                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y;
711                            break;
712                        case e_FM_PCD_PLCR_RED:
713                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_R;
714                            break;
715                        case e_FM_PCD_PLCR_OVERRIDE:
716                            pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE;
717                            break;
718                        default:
719                            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
720                    }
721
722                    break;
723                case    e_FM_PCD_PLCR_COLOR_AWARE:
724                    pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
725                    break;
726                default:
727                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
728            }
729            break;
730
731        case    e_FM_PCD_PLCR_RFC_2698:
732            /* Select algorithm MODE[ALG] = "01" */
733            pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698;
734            if (p_Profile->nonPassthroughAlgParams.comittedInfoRate > p_Profile->nonPassthroughAlgParams.peakOrAccessiveInfoRate)
735                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than comittedInfoRate."));
736            goto cont_rfc;
737        case    e_FM_PCD_PLCR_RFC_4115:
738            /* Select algorithm MODE[ALG] = "10" */
739            pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115;
740cont_rfc:
741            /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */
742            switch (p_Profile->colorMode)
743            {
744                case    e_FM_PCD_PLCR_COLOR_BLIND:
745                    pemode |= FM_PCD_PLCR_PEMODE_CBLND;
746                    break;
747                case    e_FM_PCD_PLCR_COLOR_AWARE:
748                    pemode &= ~FM_PCD_PLCR_PEMODE_CBLND;
749                    /*In color aware more select override color interpretation (MODE[OVCLR]) */
750                    switch (p_Profile->color.override)
751                    {
752                        case e_FM_PCD_PLCR_GREEN:
753                            pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK;
754                            break;
755                        case e_FM_PCD_PLCR_YELLOW:
756                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y;
757                            break;
758                        case e_FM_PCD_PLCR_RED:
759                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R;
760                            break;
761                        case e_FM_PCD_PLCR_OVERRIDE:
762                            pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC;
763                            break;
764                        default:
765                            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
766                    }
767                    break;
768                default:
769                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
770            }
771            /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */
772            switch (p_Profile->nonPassthroughAlgParams.rateMode)
773            {
774                case e_FM_PCD_PLCR_BYTE_MODE :
775                    pemode &= ~FM_PCD_PLCR_PEMODE_PKT;
776                        switch (p_Profile->nonPassthroughAlgParams.byteModeParams.frameLengthSelection)
777                        {
778                            case e_FM_PCD_PLCR_L2_FRM_LEN:
779                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L2;
780                                break;
781                            case e_FM_PCD_PLCR_L3_FRM_LEN:
782                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L3;
783                                break;
784                            case e_FM_PCD_PLCR_L4_FRM_LEN:
785                                pemode |= FM_PCD_PLCR_PEMODE_FLS_L4;
786                                break;
787                            case e_FM_PCD_PLCR_FULL_FRM_LEN:
788                                pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL;
789                                break;
790                            default:
791                                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
792                        }
793                        switch (p_Profile->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection)
794                        {
795                            case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN:
796                                pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS;
797                                break;
798                            case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN:
799                                pemode |= FM_PCD_PLCR_PEMODE_RBFLS;
800                                break;
801                            default:
802                                RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
803                        }
804                    break;
805                case e_FM_PCD_PLCR_PACKET_MODE :
806                    pemode |= FM_PCD_PLCR_PEMODE_PKT;
807                    break;
808                default:
809                    RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
810            }
811            /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET
812               mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE
813               mode with high traffic rates move the fixed point to the right to increase integer accuracy. */
814
815            /* Configure Traffic Parameters*/
816            {
817                uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0;
818
819                calcRates(h_FmPcd, &p_Profile->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp);
820
821                /*  Set Committed Information Rate (CIR) */
822                p_PlcrRegs->fmpl_pecir = cir;
823                /*  Set Committed Burst Size (CBS). */
824                p_PlcrRegs->fmpl_pecbs =  cbs;
825                /*  Set Peak Information Rate (PIR_EIR used as PIR) */
826                p_PlcrRegs->fmpl_pepepir_eir = pir_eir;
827                /*   Set Peak Burst Size (PBS_EBS used as PBS) */
828                p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs;
829
830                /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */
831                /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */
832                p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF;
833                /* Committed Rate Token Bucket Size (CTS) */
834                p_PlcrRegs->fmpl_pects = 0xFFFFFFFF;
835
836                /* Set the FPP based on calculation */
837                pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT);
838            }
839            break;  /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */
840        default:
841            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
842    }
843
844    p_PlcrRegs->fmpl_pemode = pemode;
845
846    p_PlcrRegs->fmpl_pegnia = gnia;
847    p_PlcrRegs->fmpl_peynia = ynia;
848    p_PlcrRegs->fmpl_pernia = rnia;
849
850    /* Zero Counters */
851    p_PlcrRegs->fmpl_pegpc     = 0;
852    p_PlcrRegs->fmpl_peypc     = 0;
853    p_PlcrRegs->fmpl_perpc     = 0;
854    p_PlcrRegs->fmpl_perypc    = 0;
855    p_PlcrRegs->fmpl_perrpc    = 0;
856
857    return E_OK;
858}
859
860void  FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
861{
862    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
863
864    ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
865    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE;
866}
867
868void  FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId)
869{
870    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
871
872    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
873    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE;
874}
875
876t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams)
877{
878    t_FmPcdPlcr *p_FmPcdPlcr;
879    /*uint8_t i=0;*/
880
881    UNUSED(p_FmPcd);
882    UNUSED(p_FmPcdParams);
883
884    p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr));
885    if (!p_FmPcdPlcr)
886    {
887        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED"));
888        return NULL;
889    }
890    memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr));
891    if(p_FmPcd->guestId == NCSW_MASTER_ID)
892    {
893        p_FmPcdPlcr->p_FmPcdPlcrRegs  = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm));
894        p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh    = DEFAULT_plcrAutoRefresh;
895        p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions);
896    }
897
898    p_FmPcdPlcr->numOfSharedProfiles = DEFAULT_numOfSharedPlcrProfiles;
899
900    return p_FmPcdPlcr;
901}
902
903t_Error PlcrInit(t_FmPcd *p_FmPcd)
904{
905    t_FmPcdDriverParam              *p_Param = p_FmPcd->p_FmPcdDriverParam;
906    t_FmPcdPlcr                     *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr;
907    uint32_t                        tmpReg32 = 0;
908    t_Error                         err = E_OK;
909    t_FmPcdPlcrRegs                 *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
910    t_FmPcdIpcMsg                   msg;
911    uint32_t                        replyLength;
912    t_FmPcdIpcReply                 reply;
913
914    if ((p_FmPcd->guestId != NCSW_MASTER_ID) &&
915        (p_FmPcdPlcr->numOfSharedProfiles))
916    {
917        int         i, j, index = 0;
918        uint32_t    walking1Mask = 0x80000000;
919        uint32_t    sharedProfilesMask[FM_PCD_PLCR_NUM_ENTRIES/32];
920
921        memset(sharedProfilesMask, 0, FM_PCD_PLCR_NUM_ENTRIES/32 * sizeof(uint32_t));
922        memset(&reply, 0, sizeof(reply));
923        memset(&msg, 0, sizeof(msg));
924        msg.msgId = FM_PCD_ALLOC_SHARED_PROFILES;
925        memcpy(msg.msgBody, (uint8_t *)&p_FmPcdPlcr->numOfSharedProfiles, sizeof(uint16_t));
926        replyLength = sizeof(uint32_t) + sizeof(sharedProfilesMask);
927        if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
928                                     (uint8_t*)&msg,
929                                     sizeof(msg.msgId)+ sizeof(p_FmPcdPlcr->numOfSharedProfiles),
930                                     (uint8_t*)&reply,
931                                     &replyLength,
932                                     NULL,
933                                     NULL)) != E_OK)
934            RETURN_ERROR(MAJOR, err,NO_MSG);
935        if (replyLength != (sizeof(uint32_t) + sizeof(sharedProfilesMask)))
936            RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch"));
937
938        memcpy(sharedProfilesMask, reply.replyBody, sizeof(sharedProfilesMask));
939        /* translate 8 regs of 32 bits masks into an array of up to 256 indexes. */
940        for(i = 0; i<FM_PCD_PLCR_NUM_ENTRIES/32 ; i++)
941        {
942            if(sharedProfilesMask[i])
943            {
944                for(j = 0 ; j<32 ; j++)
945                {
946                    if(sharedProfilesMask[i] & walking1Mask)
947                        p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[index++] = (uint16_t)(i*32+j);
948                    walking1Mask >>= 1;
949                }
950                walking1Mask = 0x80000000;
951            }
952        }
953        return (t_Error)reply.error;
954    }
955
956    if(p_FmPcdPlcr->numOfSharedProfiles)
957    {
958        err = PlcrAllocSharedProfiles(p_FmPcd, p_FmPcdPlcr->numOfSharedProfiles, p_FmPcd->p_FmPcdPlcr->sharedProfilesIds);
959        if(err)
960            RETURN_ERROR(MAJOR, err,NO_MSG);
961    }
962
963    /**********************FMPL_GCR******************/
964    tmpReg32 = 0;
965    tmpReg32 |= FM_PCD_PLCR_GCR_STEN;
966    if(p_Param->plcrAutoRefresh)
967        tmpReg32 |= FM_PCD_PLCR_GCR_DAR;
968    tmpReg32 |= NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME;
969
970    WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32);
971    /**********************FMPL_GCR******************/
972
973    /**********************FMPL_EEVR******************/
974    WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR));
975    /**********************FMPL_EEVR******************/
976    /**********************FMPL_EIER******************/
977    tmpReg32 = 0;
978    if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)
979    {
980        FmEnableRamsEcc(p_FmPcd->h_Fm);
981        tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC;
982    }
983    if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)
984        tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR;
985    WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32);
986    /**********************FMPL_EIER******************/
987
988    /**********************FMPL_EVR******************/
989    WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE));
990    /**********************FMPL_EVR******************/
991    /**********************FMPL_IER******************/
992    tmpReg32 = 0;
993    if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)
994        tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE;
995    if(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE )
996        tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE;
997    WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32);
998    /**********************FMPL_IER******************/
999
1000    /* register even if no interrupts enabled, to allow future enablement */
1001    FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR, PcdPlcrErrorException, p_FmPcd);
1002    FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL, PcdPlcrException, p_FmPcd);
1003
1004    /* driver initializes one DFLT profile at the last entry*/
1005    /**********************FMPL_DPMR******************/
1006    tmpReg32 = 0;
1007    WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32);
1008    p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE;
1009
1010    return E_OK;
1011}
1012
1013t_Error PlcrFree(t_FmPcd *p_FmPcd)
1014{
1015    t_Error                             err;
1016    t_FmPcdIpcSharedPlcrAllocParams     ipcSharedPlcrParams;
1017    t_FmPcdIpcMsg                       msg;
1018
1019    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR);
1020    FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL);
1021
1022    if(p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles)
1023    {
1024        if(p_FmPcd->guestId != NCSW_MASTER_ID)
1025        {
1026            int i;
1027            memset(ipcSharedPlcrParams.sharedProfilesMask, 0, sizeof(ipcSharedPlcrParams.sharedProfilesMask));
1028            /* Free resources using IPC messaging */
1029            ipcSharedPlcrParams.num = p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;
1030
1031            /* translate the allocated profile id's to a 32bit * 8regs mask */
1032            for(i = 0;i<p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;i++)
1033                ipcSharedPlcrParams.sharedProfilesMask[p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i]/32] |= (0x80000000 >> (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] % 32));
1034
1035            memset(&msg, 0, sizeof(msg));
1036            msg.msgId = FM_PCD_FREE_SHARED_PROFILES;
1037            memcpy(msg.msgBody, &ipcSharedPlcrParams, sizeof(ipcSharedPlcrParams));
1038            if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1039                                         (uint8_t*)&msg,
1040                                         sizeof(msg.msgId)+sizeof(ipcSharedPlcrParams),
1041                                         NULL,
1042                                         NULL,
1043                                         NULL,
1044                                         NULL)) != E_OK)
1045                RETURN_ERROR(MAJOR, err,NO_MSG);
1046        }
1047       /* else
1048            PlcrFreeSharedProfiles(p_FmPcd, p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles, p_FmPcd->p_FmPcdPlcr->sharedProfilesIds);*/
1049    }
1050    return E_OK;
1051}
1052
1053t_Error     FmPcdPlcrGetAbsoluteProfileId(t_Handle                      h_FmPcd,
1054                                          e_FmPcdProfileTypeSelection   profileType,
1055                                          t_Handle                      h_FmPort,
1056                                          uint16_t                      relativeProfile,
1057                                          uint16_t                      *p_AbsoluteId)
1058{
1059    t_FmPcd         *p_FmPcd            = (t_FmPcd*)h_FmPcd;
1060    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
1061    uint8_t         i;
1062
1063    switch (profileType)
1064    {
1065        case e_FM_PCD_PLCR_PORT_PRIVATE:
1066            /* get port PCD id from port handle */
1067            for(i=0;i<FM_MAX_NUM_OF_PORTS;i++)
1068                if(p_FmPcd->p_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort)
1069                    break;
1070            if (i ==  FM_MAX_NUM_OF_PORTS)
1071                RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle."));
1072
1073            if(!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
1074                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles"));
1075            if(relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles)
1076                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
1077            *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile);
1078            break;
1079        case e_FM_PCD_PLCR_SHARED:
1080            if(relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles)
1081                RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range"));
1082            *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]);
1083            break;
1084        default:
1085            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type"));
1086    }
1087    return E_OK;
1088}
1089
1090uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId)
1091{
1092    t_FmPcd         *p_FmPcd = (t_FmPcd *)h_FmPcd;
1093    uint16_t        swPortIndex = 0;
1094
1095    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
1096
1097    return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase;
1098}
1099
1100uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId)
1101{
1102    t_FmPcd         *p_FmPcd = (t_FmPcd *)h_FmPcd;
1103    uint16_t        swPortIndex = 0;
1104
1105    HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId);
1106
1107    return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles;
1108
1109}
1110uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId)
1111{
1112    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
1113                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT));
1114}
1115
1116uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId)
1117{
1118    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
1119                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
1120                      FM_PCD_PLCR_PAR_PWSEL_MASK);
1121}
1122
1123bool    FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg)
1124{
1125
1126    if(profileModeReg & FM_PCD_PLCR_PEMODE_PI)
1127        return TRUE;
1128    else
1129        return FALSE;
1130}
1131
1132uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId)
1133{
1134    return (uint32_t)(FM_PCD_PLCR_PAR_GO |
1135                      FM_PCD_PLCR_PAR_R |
1136                      ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) |
1137                      FM_PCD_PLCR_PAR_PWSEL_MASK);
1138}
1139
1140uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter)
1141{
1142    switch(counter)
1143    {
1144        case(e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER):
1145            return FM_PCD_PLCR_PAR_PWSEL_PEGPC;
1146        case(e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER):
1147            return FM_PCD_PLCR_PAR_PWSEL_PEYPC;
1148        case(e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) :
1149            return FM_PCD_PLCR_PAR_PWSEL_PERPC;
1150        case(e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) :
1151            return FM_PCD_PLCR_PAR_PWSEL_PERYPC;
1152        case(e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) :
1153            return FM_PCD_PLCR_PAR_PWSEL_PERRPC;
1154       default:
1155            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
1156            return 0;
1157    }
1158}
1159
1160uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red)
1161{
1162
1163    uint32_t tmpReg32 = 0;
1164
1165    if(green)
1166        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
1167    if(yellow)
1168        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
1169    if(red)
1170        tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
1171
1172    return tmpReg32;
1173}
1174
1175void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction)
1176{
1177    t_FmPcd     *p_FmPcd = (t_FmPcd*)h_FmPcd;
1178
1179   ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid);
1180
1181    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = requiredAction;
1182}
1183
1184t_Error FmPcdPlcrProfileTryLock(t_Handle h_FmPcd, uint16_t profileId, bool intr)
1185{
1186    t_FmPcd         *p_FmPcd = (t_FmPcd *)h_FmPcd;
1187    bool            ans;
1188    if (intr)
1189        ans = TRY_LOCK(NULL, &p_FmPcd->p_FmPcdPlcr->profiles[profileId].lock);
1190    else
1191        ans = TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->p_FmPcdPlcr->profiles[profileId].lock);
1192    if (ans)
1193        return E_OK;
1194    return ERROR_CODE(E_BUSY);
1195}
1196
1197void FmPcdPlcrReleaseProfileLock(t_Handle h_FmPcd, uint16_t profileId)
1198{
1199    RELEASE_LOCK(((t_FmPcd*)h_FmPcd)->p_FmPcdPlcr->profiles[profileId].lock);
1200}
1201
1202/**************************************************/
1203/*............Policer API.........................*/
1204/**************************************************/
1205
1206t_Handle FM_PCD_PlcrSetProfile(t_Handle     h_FmPcd,
1207                               t_FmPcdPlcrProfileParams *p_Profile)
1208{
1209    t_FmPcd                             *p_FmPcd            = (t_FmPcd*)h_FmPcd;
1210    t_FmPcdPlcrRegs                     *p_FmPcdPlcrRegs;
1211    t_FmPcdPlcrInterModuleProfileRegs   plcrProfileReg;
1212    uint32_t                            intFlags;
1213    uint16_t                            absoluteProfileId;
1214    t_Error                             err = E_OK;
1215    uint32_t                            tmpReg32;
1216
1217    SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL);
1218    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL);
1219    SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL);
1220
1221    if (p_FmPcd->h_Hc)
1222        return FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, p_Profile);
1223
1224    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
1225    SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL);
1226
1227    if (p_Profile->modify)
1228    {
1229        absoluteProfileId = (uint16_t)(PTR_TO_UINT(p_Profile->id.h_Profile)-1);
1230        if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
1231        {
1232            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
1233            return NULL;
1234        }
1235        if (FmPcdPlcrProfileTryLock(p_FmPcd, absoluteProfileId, FALSE))
1236            return NULL;
1237    }
1238    else
1239    {
1240        intFlags = FmPcdLock(p_FmPcd);
1241        err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd,
1242                                            p_Profile->id.newParams.profileType,
1243                                            p_Profile->id.newParams.h_FmPort,
1244                                            p_Profile->id.newParams.relativeProfileId,
1245                                            &absoluteProfileId);
1246        if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES)
1247        {
1248            REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
1249            return NULL;
1250        }
1251        if(err)
1252        {
1253            FmPcdUnlock(p_FmPcd, intFlags);
1254            REPORT_ERROR(MAJOR, err, NO_MSG);
1255            return NULL;
1256        }
1257        err = FmPcdPlcrProfileTryLock(p_FmPcd, absoluteProfileId, TRUE);
1258        FmPcdUnlock(p_FmPcd, intFlags);
1259        if (err)
1260            return NULL;
1261    }
1262
1263    /* if no override, check first that this profile is unused */
1264    if(!p_Profile->modify)
1265    {
1266        /* read specified profile into profile registers */
1267        tmpReg32 = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId);
1268        intFlags = FmPcdLock(p_FmPcd);
1269        WritePar(p_FmPcd, tmpReg32);
1270        tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode);
1271        FmPcdUnlock(p_FmPcd, intFlags);
1272        if (tmpReg32 & FM_PCD_PLCR_PEMODE_PI)
1273        {
1274            RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock);
1275            REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used"));
1276            return NULL;
1277        }
1278    }
1279
1280    memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrInterModuleProfileRegs));
1281
1282    err =  FmPcdPlcrBuildProfile(h_FmPcd, p_Profile, &plcrProfileReg);
1283    if(err)
1284    {
1285        RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock);
1286        REPORT_ERROR(MAJOR, err, NO_MSG);
1287        return NULL;
1288    }
1289
1290    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnGreen = p_Profile->nextEngineOnGreen;
1291    memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnGreen, &(p_Profile->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams));
1292
1293    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnYellow = p_Profile->nextEngineOnYellow;
1294    memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnYellow, &(p_Profile->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams));
1295
1296    p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].nextEngineOnRed = p_Profile->nextEngineOnRed;
1297    memcpy(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].paramsOnRed, &(p_Profile->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams));
1298
1299    intFlags = FmPcdLock(p_FmPcd);
1300    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode);
1301    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia);
1302    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia);
1303    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia);
1304    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir  , plcrProfileReg.fmpl_pecir);
1305    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs  , plcrProfileReg.fmpl_pecbs);
1306    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir);
1307    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs);
1308    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts  , plcrProfileReg.fmpl_pelts);
1309    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects  , plcrProfileReg.fmpl_pects);
1310    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets);
1311    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc  , plcrProfileReg.fmpl_pegpc);
1312    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc  , plcrProfileReg.fmpl_peypc);
1313    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc  , plcrProfileReg.fmpl_perpc);
1314    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc);
1315    WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc);
1316
1317    tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId);
1318    WritePar(p_FmPcd, tmpReg32);
1319
1320    FmPcdUnlock(p_FmPcd, intFlags);
1321
1322    if (!p_Profile->modify)
1323        FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId);
1324
1325    RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].lock);
1326
1327    return UINT_TO_PTR((uint64_t)absoluteProfileId+1);
1328}
1329
1330t_Error FM_PCD_PlcrDeleteProfile(t_Handle h_FmPcd, t_Handle h_Profile)
1331{
1332    t_FmPcd         *p_FmPcd = (t_FmPcd*)h_FmPcd;
1333    uint16_t        profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1);
1334    uint32_t        tmpReg32, intFlags;
1335
1336    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1337    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
1338    SANITY_CHECK_RETURN_ERROR((profileIndx < FM_PCD_PLCR_NUM_ENTRIES), E_INVALID_SELECTION);
1339
1340    if (p_FmPcd->h_Hc)
1341        return FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile);
1342
1343    FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx);
1344
1345    intFlags = FmPcdLock(p_FmPcd);
1346    WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI);
1347
1348    tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx);
1349    WritePar(p_FmPcd, tmpReg32);
1350    FmPcdUnlock(p_FmPcd, intFlags);
1351
1352    return E_OK;
1353}
1354
1355/* ......... */
1356/***************************************************/
1357/*............Policer Profile Counter..............*/
1358/***************************************************/
1359uint32_t FM_PCD_PlcrGetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter)
1360{
1361    t_FmPcd         *p_FmPcd    = (t_FmPcd*)h_FmPcd;
1362    uint16_t        profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1);
1363    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
1364    uint32_t        intFlags, counterVal = 0;
1365
1366    SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0);
1367    SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0);
1368    SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, 0);
1369
1370    if (p_FmPcd->h_Hc)
1371        return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter);
1372
1373    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
1374    SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0);
1375
1376    if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
1377    {
1378        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big "));
1379        return 0;
1380    }
1381    intFlags = FmPcdLock(p_FmPcd);
1382    WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
1383
1384    if(!FmPcdPlcrHwProfileIsValid(GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode)))
1385    {
1386        REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized profile"));
1387        FmPcdUnlock(p_FmPcd, intFlags);
1388        return 0;
1389    }
1390
1391    switch (counter)
1392    {
1393        case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
1394            counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc));
1395            break;
1396        case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
1397            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc);
1398            break;
1399        case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
1400            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc);
1401            break;
1402        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
1403            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc);
1404            break;
1405        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
1406            counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc);
1407            break;
1408        default:
1409            REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
1410            break;
1411    }
1412    FmPcdUnlock(p_FmPcd, intFlags);
1413
1414    return counterVal;
1415}
1416
1417
1418t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction)
1419{
1420    t_FmPcd         *p_FmPcd           = (t_FmPcd *)h_FmPcd;
1421    t_FmPcdPlcr     *p_FmPcdPlcr        = p_FmPcd->p_FmPcdPlcr;
1422    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs    = p_FmPcdPlcr->p_FmPcdPlcrRegs;
1423    uint32_t        tmpReg32, intFlags;
1424
1425    if (p_FmPcd->h_Hc)
1426        return FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction);
1427
1428    if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES)
1429        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range"));
1430
1431    if (FmPcdPlcrProfileTryLock(p_FmPcd, profileIndx, FALSE))
1432        RETURN_ERROR(MAJOR, E_INVALID_STATE,("Lock on PP FAILED"));
1433
1434    intFlags = FmPcdLock(p_FmPcd);
1435    WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx));
1436
1437    if(!FmPcdPlcrHwProfileIsValid(GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode)))
1438    {
1439        FmPcdUnlock(p_FmPcd, intFlags);
1440        RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].lock);
1441        RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid"));
1442    }
1443
1444    ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].valid);
1445
1446    if(!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].pointedOwners ||
1447       !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction))
1448    {
1449        if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA)
1450        {
1451            if((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) ||
1452               (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) ||
1453               (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE))
1454            {
1455                FmPcdUnlock(p_FmPcd, intFlags);
1456                RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE"));
1457            }
1458
1459            if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME)
1460            {
1461                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia);
1462                if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
1463                {
1464                    FmPcdUnlock(p_FmPcd, intFlags);
1465                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
1466                }
1467                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
1468                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32);
1469                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
1470                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA;
1471                WritePar(p_FmPcd, tmpReg32);
1472            }
1473
1474            if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME)
1475            {
1476                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia);
1477                if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
1478                {
1479                    FmPcdUnlock(p_FmPcd, intFlags);
1480                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
1481                }
1482                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
1483                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32);
1484                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
1485                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA;
1486                WritePar(p_FmPcd, tmpReg32);
1487            }
1488
1489            if(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME)
1490            {
1491                tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia);
1492                if(!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)))
1493                {
1494                    FmPcdUnlock(p_FmPcd, intFlags);
1495                    RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE"));
1496                }
1497                tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA;
1498                WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32);
1499                tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
1500                tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA;
1501                WritePar(p_FmPcd, tmpReg32);
1502            }
1503        }
1504    }
1505    FmPcdUnlock(p_FmPcd, intFlags);
1506
1507    p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].pointedOwners += 1;
1508    p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction |= requiredAction;
1509
1510    RELEASE_LOCK(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].lock);
1511
1512    return E_OK;
1513}
1514
1515t_Error FM_PCD_PlcrSetProfileCounter(t_Handle h_FmPcd, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value)
1516{
1517    t_FmPcd         *p_FmPcd    = (t_FmPcd*)h_FmPcd;
1518    uint16_t        profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1);
1519    t_FmPcdPlcrRegs *p_FmPcdPlcrRegs;
1520    uint32_t        tmpReg32, intFlags;
1521
1522    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1523    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
1524    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
1525
1526    if (p_FmPcd->h_Hc)
1527        return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value);
1528
1529    p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs;
1530    SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE);
1531
1532    intFlags = FmPcdLock(p_FmPcd);
1533    switch (counter)
1534    {
1535        case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER:
1536             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value);
1537             break;
1538        case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER:
1539             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value);
1540             break;
1541        case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER:
1542             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value);
1543             break;
1544        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER:
1545             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value);
1546             break;
1547        case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER:
1548             WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value);
1549             break;
1550        default:
1551            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG);
1552    }
1553
1554    /*  Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM =
1555     *  Profile Number, PWSEL=0xFFFF (select all words).
1556     */
1557    tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx);
1558    tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter);
1559    WritePar(p_FmPcd, tmpReg32);
1560    FmPcdUnlock(p_FmPcd, intFlags);
1561
1562    return E_OK;
1563}
1564
1565t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles)
1566{
1567   t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd;
1568
1569    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1570    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE);
1571    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
1572
1573    p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles;
1574
1575    return E_OK;
1576}
1577
1578
1579/* ... */
1580
1581#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0))
1582t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd)
1583{
1584    t_FmPcd             *p_FmPcd = (t_FmPcd*)h_FmPcd;
1585    int                 i = 0;
1586    t_FmPcdIpcMsg       msg;
1587
1588    DECLARE_DUMP;
1589
1590    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1591    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
1592    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
1593
1594    if(p_FmPcd->guestId != NCSW_MASTER_ID)
1595    {
1596        memset(&msg, 0, sizeof(msg));
1597        msg.msgId = FM_PCD_PLCR_DUMP_REGS;
1598        return XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1599                                 (uint8_t*)&msg,
1600                                 sizeof(msg.msgId),
1601                                 NULL,
1602                                 NULL,
1603                                 NULL,
1604                                 NULL);
1605    }
1606    else
1607    {
1608        DUMP_SUBTITLE(("\n"));
1609        DUMP_TITLE(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, ("FmPcdPlcrRegs Regs"));
1610
1611        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_gcr);
1612        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_gsr);
1613        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_evr);
1614        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ier);
1615        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ifr);
1616        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eevr);
1617        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eier);
1618        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_eifr);
1619        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rpcnt);
1620        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_ypcnt);
1621        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rrpcnt);
1622        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_rypcnt);
1623        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_tpcnt);
1624        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_flmcnt);
1625
1626        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_serc);
1627        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_upcr);
1628        DUMP_VAR(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs,fmpl_dpmr);
1629
1630
1631        DUMP_TITLE(&p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr, ("fmpl_pmr"));
1632        DUMP_SUBSTRUCT_ARRAY(i, 63)
1633        {
1634            DUMP_MEMORY(&p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr[i], sizeof(uint32_t));
1635        }
1636
1637        return E_OK;
1638    }
1639}
1640
1641t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_FmPcd, t_Handle h_Profile)
1642{
1643    t_FmPcd                             *p_FmPcd = (t_FmPcd*)h_FmPcd;
1644    t_FmPcdPlcrInterModuleProfileRegs   *p_ProfilesRegs;
1645    uint32_t                            tmpReg, intFlags;
1646    uint16_t                            profileIndx = (uint16_t)(PTR_TO_UINT(h_Profile)-1);
1647    t_FmPcdIpcMsg                       msg;
1648
1649    DECLARE_DUMP;
1650
1651    SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE);
1652    SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE);
1653    SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE);
1654
1655    if(p_FmPcd->guestId != NCSW_MASTER_ID)
1656    {
1657        memset(&msg, 0, sizeof(msg));
1658        msg.msgId = FM_PCD_PLCR_PROFILE_DUMP_REGS;
1659        memcpy(msg.msgBody, (uint8_t *)&h_Profile, sizeof(uint32_t));
1660        return XX_IpcSendMessage(p_FmPcd->h_IpcSession,
1661                                 (uint8_t*)&msg,
1662                                 sizeof(msg.msgId) + sizeof(uint32_t),
1663                                 NULL,
1664                                 NULL,
1665                                 NULL,
1666                                 NULL);
1667    }
1668    else
1669    {
1670        DUMP_SUBTITLE(("\n"));
1671        DUMP_TITLE(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, ("FmPcdPlcrRegs Profile Regs"));
1672
1673        p_ProfilesRegs = &p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs;
1674
1675        tmpReg = FmPcdPlcrBuildReadPlcrActionReg((uint16_t)profileIndx);
1676        intFlags = FmPcdLock(p_FmPcd);
1677        WritePar(p_FmPcd, tmpReg);
1678
1679        DUMP_TITLE(p_ProfilesRegs, ("Profile %d regs", profileIndx));
1680
1681        DUMP_VAR(p_ProfilesRegs, fmpl_pemode);
1682        DUMP_VAR(p_ProfilesRegs, fmpl_pegnia);
1683        DUMP_VAR(p_ProfilesRegs, fmpl_peynia);
1684        DUMP_VAR(p_ProfilesRegs, fmpl_pernia);
1685        DUMP_VAR(p_ProfilesRegs, fmpl_pecir);
1686        DUMP_VAR(p_ProfilesRegs, fmpl_pecbs);
1687        DUMP_VAR(p_ProfilesRegs, fmpl_pepepir_eir);
1688        DUMP_VAR(p_ProfilesRegs, fmpl_pepbs_ebs);
1689        DUMP_VAR(p_ProfilesRegs, fmpl_pelts);
1690        DUMP_VAR(p_ProfilesRegs, fmpl_pects);
1691        DUMP_VAR(p_ProfilesRegs, fmpl_pepts_ets);
1692        DUMP_VAR(p_ProfilesRegs, fmpl_pegpc);
1693        DUMP_VAR(p_ProfilesRegs, fmpl_peypc);
1694        DUMP_VAR(p_ProfilesRegs, fmpl_perpc);
1695        DUMP_VAR(p_ProfilesRegs, fmpl_perypc);
1696        DUMP_VAR(p_ProfilesRegs, fmpl_perrpc);
1697        FmPcdUnlock(p_FmPcd, intFlags);
1698
1699        return E_OK;
1700    }
1701}
1702#endif /* (defined(DEBUG_ERRORS) && ... */
1703