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_replic.c
36
37 @Description   FM frame replicator
38*//***************************************************************************/
39#include "std_ext.h"
40#include "error_ext.h"
41#include "string_ext.h"
42#include "debug_ext.h"
43#include "fm_pcd_ext.h"
44#include "fm_muram_ext.h"
45#include "fm_common.h"
46#include "fm_hc.h"
47#include "fm_replic.h"
48#include "fm_cc.h"
49#include "list_ext.h"
50
51
52/****************************************/
53/*       static functions               */
54/****************************************/
55static uint8_t  GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup,
56                                  uint32_t              memberIndex,
57                                  bool                  isAddOperation)
58{
59    uint8_t     memberPosition;
60    uint32_t    lastMemberIndex;
61
62    ASSERT_COND(p_ReplicGroup);
63
64    /* the last member index is different between add and remove operation -
65    in case of remove - this is exactly the last member index
66    in case of add - this is the last member index + 1 - e.g.
67    if we have 4 members, the index of the actual last member is 3(because the
68    index starts from 0) therefore in order to add a new member as the last
69    member we shall use memberIndex = 4 and not 3
70    */
71    if (isAddOperation)
72        lastMemberIndex = p_ReplicGroup->numOfEntries;
73    else
74        lastMemberIndex = p_ReplicGroup->numOfEntries-1;
75
76    /* last */
77    if (memberIndex == lastMemberIndex)
78        memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX;
79    else
80    {
81        /* first */
82        if (memberIndex == 0)
83            memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX;
84        else
85        {
86            /* middle */
87            ASSERT_COND(memberIndex < lastMemberIndex);
88            memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX;
89        }
90    }
91    return memberPosition;
92}
93
94static t_Error MemberCheckParams(t_Handle                  h_FmPcd,
95                                 t_FmPcdCcNextEngineParams *p_MemberParams)
96{
97    t_Error         err;
98
99
100    if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) &&
101        (p_MemberParams->nextEngine != e_FM_PCD_KG)   &&
102        (p_MemberParams->nextEngine != e_FM_PCD_PLCR))
103        RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer"));
104
105    /* check the regular parameters of the next engine */
106    err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE);
107    if (err)
108        RETURN_ERROR(MAJOR, err, ("member next engine parameters"));
109
110    return E_OK;
111}
112
113static t_Error CheckParams(t_Handle                     h_FmPcd,
114                           t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
115{
116    int             i;
117    t_Error         err;
118
119    /* check that max num of entries is at least 2 */
120    if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES))
121        RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
122
123    /* check that number of entries is greater than zero */
124    if (!p_ReplicGroupParam->numOfEntries)
125        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero"));
126
127    /* check that max num of entries is equal or greater than number of entries */
128    if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries)
129        RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries"));
130
131    for (i=0; i<p_ReplicGroupParam->numOfEntries; i++)
132    {
133        err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]);
134        if (err)
135            RETURN_ERROR(MAJOR, err, ("member check parameters"));
136    }
137    return E_OK;
138}
139
140static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
141{
142    t_FmPcdFrmReplicMember  *p_ReplicMember = NULL;
143    t_List                  *p_Next;
144
145    if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList))
146    {
147        p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList);
148        p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node);
149        ASSERT_COND(p_ReplicMember);
150        LIST_DelAndInit(p_Next);
151    }
152    return p_ReplicMember;
153}
154
155static void PutAvailableMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
156                               t_FmPcdFrmReplicMember   *p_ReplicMember)
157{
158    LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList);
159}
160
161static void AddMemberToList(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
162                            t_FmPcdFrmReplicMember  *p_CurrentMember,
163                            t_List                  *p_ListHead)
164{
165    LIST_Add(&p_CurrentMember->node, p_ListHead);
166
167    p_ReplicGroup->numOfEntries++;
168}
169
170static void RemoveMemberFromList(t_FmPcdFrmReplicGroup  *p_ReplicGroup,
171                                 t_FmPcdFrmReplicMember *p_CurrentMember)
172{
173    ASSERT_COND(p_ReplicGroup->numOfEntries);
174    LIST_DelAndInit(&p_CurrentMember->node);
175    p_ReplicGroup->numOfEntries--;
176}
177
178static void LinkSourceToMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
179                               t_AdOfTypeContLookup     *p_SourceTd,
180                               t_FmPcdFrmReplicMember   *p_ReplicMember)
181{
182    t_FmPcd             *p_FmPcd;
183
184    ASSERT_COND(p_SourceTd);
185    ASSERT_COND(p_ReplicMember);
186    ASSERT_COND(p_ReplicGroup);
187    ASSERT_COND(p_ReplicGroup->h_FmPcd);
188
189    /* Link the first member in the group to the source TD */
190    p_FmPcd = p_ReplicGroup->h_FmPcd;
191
192    WRITE_UINT32(p_SourceTd->matchTblPtr,
193        (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) -
194                        p_FmPcd->physicalMuramBase));
195}
196
197static void LinkMemberToMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
198                               t_FmPcdFrmReplicMember   *p_CurrentMember,
199                               t_FmPcdFrmReplicMember   *p_NextMember)
200{
201    t_AdOfTypeResult    *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd;
202    t_AdOfTypeResult    *p_NextReplicAd = NULL;
203    t_FmPcd             *p_FmPcd;
204    uint32_t            offset = 0;
205
206    /* Check if the next member exists or it's NULL (- means that this is the last member) */
207    if (p_NextMember)
208    {
209        p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd;
210        p_FmPcd = p_ReplicGroup->h_FmPcd;
211        offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase));
212        offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT);
213    }
214
215    /* link the current AD to point to the AD of the next member */
216    WRITE_UINT32(p_CurrReplicAd->res, offset);
217}
218
219static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
220                                void                    *p_OldDescriptor,
221                                void                    *p_NewDescriptor)
222{
223    t_Handle            h_Hc;
224    t_Error             err;
225    t_FmPcd             *p_FmPcd;
226
227    ASSERT_COND(p_ReplicGroup);
228    ASSERT_COND(p_ReplicGroup->h_FmPcd);
229    ASSERT_COND(p_OldDescriptor);
230    ASSERT_COND(p_NewDescriptor);
231
232    p_FmPcd = p_ReplicGroup->h_FmPcd;
233    h_Hc = FmPcdGetHcHandle(p_FmPcd);
234    if (!h_Hc)
235        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command"));
236
237    err = FmHcPcdCcDoDynamicChange(h_Hc,
238                                   (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase),
239                                   (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase));
240    if (err)
241        RETURN_ERROR(MAJOR, err, ("Dynamic change host command"));
242
243    return E_OK;
244}
245
246static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last)
247{
248    t_AdOfTypeResult    *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd;
249    uint32_t            tmp;
250
251    tmp = GET_UINT32(p_CurrReplicAd->plcrProfile);
252    if (last)
253        /* clear the NL bit in case it's the last member in the group*/
254        WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT));
255    else
256        /* set the NL bit in case it's not the last member in the group */
257        WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT));
258
259    /* set FR bit in the action descriptor */
260    tmp = GET_UINT32(p_CurrReplicAd->nia);
261    WRITE_UINT32(p_CurrReplicAd->nia,
262        (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE ));
263}
264
265static void BuildSourceTd(void *p_Ad)
266{
267    t_AdOfTypeContLookup    *p_SourceTd;
268
269    ASSERT_COND(p_Ad);
270
271    p_SourceTd = (t_AdOfTypeContLookup *)p_Ad;
272
273    IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
274
275    /* initialize the source table descriptor */
276    WRITE_UINT32(p_SourceTd->ccAdBase,     FM_PCD_AD_CONT_LOOKUP_TYPE);
277    WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE);
278}
279
280static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
281                                              t_FmPcdFrmReplicMember  *p_NextMember,
282                                              t_FmPcdFrmReplicMember  *p_CurrentMember,
283                                              bool                    sourceDescriptor,
284                                              bool                    last)
285{
286    t_FmPcd                 *p_FmPcd;
287    t_FmPcdFrmReplicMember  shadowMember;
288    t_Error                 err;
289
290    ASSERT_COND(p_ReplicGroup);
291    ASSERT_COND(p_ReplicGroup->h_FmPcd);
292
293    p_FmPcd = p_ReplicGroup->h_FmPcd;
294    ASSERT_COND(p_FmPcd->p_CcShadow);
295
296    if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))
297        return ERROR_CODE(E_BUSY);
298
299    if (sourceDescriptor)
300    {
301        BuildSourceTd(p_FmPcd->p_CcShadow);
302        LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember);
303
304        /* Modify the source table descriptor according to the prepared shadow descriptor */
305        err = ModifyDescriptor(p_ReplicGroup,
306                               p_ReplicGroup->p_SourceTd,
307                               p_FmPcd->p_CcShadow/* new prepared source td */);
308
309        RELEASE_LOCK(p_FmPcd->shadowLock);
310        if (err)
311            RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor"));
312
313    }
314    else
315    {
316        IO2IOCpy32(p_FmPcd->p_CcShadow,
317                   p_CurrentMember->p_MemberAd,
318                   FM_PCD_CC_AD_ENTRY_SIZE);
319
320        /* update the last bit in the shadow ad */
321        FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last);
322
323        shadowMember.p_MemberAd = p_FmPcd->p_CcShadow;
324
325        /* update the next FR member index */
326        LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember);
327
328        /* Modify the next member according to the prepared shadow descriptor */
329        err = ModifyDescriptor(p_ReplicGroup,
330                               p_CurrentMember->p_MemberAd,
331                               p_FmPcd->p_CcShadow);
332
333        RELEASE_LOCK(p_FmPcd->shadowLock);
334        if (err)
335            RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor"));
336    }
337
338
339    return E_OK;
340}
341
342static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
343                                                uint16_t                memberIndex)
344{
345    int                     i=0;
346    t_List                  *p_Pos;
347    t_FmPcdFrmReplicMember  *p_Member = NULL;
348
349    LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList)
350    {
351        if (i == memberIndex)
352        {
353            p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node);
354            return p_Member;
355        }
356        i++;
357    }
358    return p_Member;
359}
360
361static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)
362{
363    t_FmPcdFrmReplicMember  *p_CurrentMember;
364    t_Handle                h_Muram;
365
366    ASSERT_COND(p_ReplicGroup);
367
368    h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
369    ASSERT_COND(h_Muram);
370
371    /* Initialize an internal structure of a member to add to the available members list */
372    p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember));
373    if (!p_CurrentMember)
374        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member"));
375
376    memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember));
377
378    /* Allocate the member AD */
379    p_CurrentMember->p_MemberAd =
380        (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram,
381                                             FM_PCD_CC_AD_ENTRY_SIZE,
382                                             FM_PCD_CC_AD_TABLE_ALIGN);
383    if (!p_CurrentMember->p_MemberAd)
384    {
385        XX_Free(p_CurrentMember);
386        RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table"));
387    }
388    IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
389
390    /* Add the new member to the available members list */
391    LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList));
392
393    return E_OK;
394}
395
396static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup     *p_ReplicGroup,
397                                          t_FmPcdCcNextEngineParams *p_MemberParams,
398                                          bool                      last)
399{
400    t_FmPcdFrmReplicMember  *p_CurrentMember = NULL;
401
402    ASSERT_COND(p_ReplicGroup);
403
404    /* Get an available member from the internal members list */
405    p_CurrentMember = GetAvailableMember(p_ReplicGroup);
406    if (!p_CurrentMember)
407    {
408        REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member"));
409        return NULL;
410    }
411    p_CurrentMember->h_Manip = NULL;
412
413    /* clear the Ad of the new member */
414    IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
415
416    INIT_LIST(&p_CurrentMember->node);
417
418    /* Initialize the Ad of the member */
419    NextStepAd(p_CurrentMember->p_MemberAd,
420               NULL,
421               p_MemberParams,
422               p_ReplicGroup->h_FmPcd);
423
424    /* save Manip handle (for free needs) */
425    if (p_MemberParams->h_Manip)
426        p_CurrentMember->h_Manip = p_MemberParams->h_Manip;
427
428    /* Initialize the relevant frame replicator fields in the AD */
429    FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last);
430
431    return p_CurrentMember;
432}
433
434static void FreeMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
435                       t_FmPcdFrmReplicMember   *p_Member)
436{
437    /* Note: Can't free the member AD just returns the member to the available
438       member list - therefore only memset the AD */
439
440    /* zero the AD */
441    IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);
442
443
444    /* return the member to the available members list */
445    PutAvailableMember(p_ReplicGroup, p_Member);
446}
447
448static t_Error RemoveMember(t_FmPcdFrmReplicGroup   *p_ReplicGroup,
449                            uint16_t                memberIndex)
450{
451    t_FmPcd                 *p_FmPcd = NULL;
452    t_FmPcdFrmReplicMember  *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL;
453    t_Error                 err;
454    uint8_t                 memberPosition;
455
456    p_FmPcd         = p_ReplicGroup->h_FmPcd;
457    ASSERT_COND(p_FmPcd);
458    UNUSED(p_FmPcd);
459
460    p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
461    ASSERT_COND(p_CurrentMember);
462
463    /* determine the member position in the group */
464    memberPosition = GetMemberPosition(p_ReplicGroup,
465                                       memberIndex,
466                                       FALSE/*remove operation*/);
467
468    switch (memberPosition)
469    {
470        case FRM_REPLIC_FIRST_MEMBER_INDEX:
471            p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
472            ASSERT_COND(p_NextMember);
473
474            /* update the source td itself by using a host command */
475            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
476                                                 p_NextMember,
477                                                 NULL,
478                                                 TRUE/*sourceDescriptor*/,
479                                                 FALSE/*last*/);
480            break;
481
482        case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
483            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
484            ASSERT_COND(p_PreviousMember);
485
486            p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));
487            ASSERT_COND(p_NextMember);
488
489            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
490                                                 p_NextMember,
491                                                 p_PreviousMember,
492                                                 FALSE/*sourceDescriptor*/,
493                                                 FALSE/*last*/);
494
495            break;
496
497        case FRM_REPLIC_LAST_MEMBER_INDEX:
498            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
499            ASSERT_COND(p_PreviousMember);
500
501            err = BuildShadowAndModifyDescriptor(p_ReplicGroup,
502                                                 NULL,
503                                                 p_PreviousMember,
504                                                 FALSE/*sourceDescriptor*/,
505                                                 TRUE/*last*/);
506            break;
507
508        default:
509            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member"));
510    }
511
512    if (err)
513        RETURN_ERROR(MAJOR, err, NO_MSG);
514
515    if (p_CurrentMember->h_Manip)
516    {
517        FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
518        p_CurrentMember->h_Manip = NULL;
519    }
520
521    /* remove the member from the driver internal members list */
522    RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
523
524    /* return the member to the available members list */
525    FreeMember(p_ReplicGroup, p_CurrentMember);
526
527    return E_OK;
528}
529
530static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup)
531{
532    int                     i, j;
533    t_Handle                h_Muram;
534    t_FmPcdFrmReplicMember  *p_Member, *p_CurrentMember;
535
536    if (p_ReplicGroup)
537    {
538        ASSERT_COND(p_ReplicGroup->h_FmPcd);
539        h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
540        ASSERT_COND(h_Muram);
541
542        /* free the source table descriptor */
543        if (p_ReplicGroup->p_SourceTd)
544        {
545            FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd);
546            p_ReplicGroup->p_SourceTd = NULL;
547        }
548
549        /* Remove all members from the members linked list (hw and sw) and
550           return the members to the available members list */
551        if (p_ReplicGroup->numOfEntries)
552        {
553            j = p_ReplicGroup->numOfEntries-1;
554
555            /* manually removal of the member because there are no owners of
556               this group */
557            for (i=j; i>=0; i--)
558            {
559                p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/);
560                ASSERT_COND(p_CurrentMember);
561
562                if (p_CurrentMember->h_Manip)
563                {
564                    FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);
565                    p_CurrentMember->h_Manip = NULL;
566                }
567
568                /* remove the member from the internal driver members list */
569                RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);
570
571                /* return the member to the available members list */
572                FreeMember(p_ReplicGroup, p_CurrentMember);
573            }
574        }
575
576        /* Free members AD */
577        for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
578        {
579            p_Member = GetAvailableMember(p_ReplicGroup);
580            ASSERT_COND(p_Member);
581            if (p_Member->p_MemberAd)
582            {
583                FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd);
584                p_Member->p_MemberAd = NULL;
585            }
586            XX_Free(p_Member);
587        }
588
589        /* release the group lock */
590        if (p_ReplicGroup->p_Lock)
591            FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock);
592
593        /* free the replicator group */
594        XX_Free(p_ReplicGroup);
595    }
596}
597
598
599/*****************************************************************************/
600/*              Inter-module API routines                                    */
601/*****************************************************************************/
602
603/* NOTE: the inter-module routines are locked by cc in case of using them */
604void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup)
605{
606    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
607    ASSERT_COND(p_ReplicGroup);
608
609    return (p_ReplicGroup->p_SourceTd);
610}
611
612void FrmReplicGroupUpdateAd(t_Handle  h_ReplicGroup,
613                            void      *p_Ad,
614                            t_Handle  *h_AdNew)
615{
616    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
617    t_AdOfTypeResult    *p_AdResult = (t_AdOfTypeResult*)p_Ad;
618    t_FmPcd             *p_FmPcd;
619
620    ASSERT_COND(p_ReplicGroup);
621    p_FmPcd = p_ReplicGroup->h_FmPcd;
622
623    /* build a bypass ad */
624    WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE |
625        (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase));
626
627    *h_AdNew = NULL;
628}
629
630void  FrmReplicGroupUpdateOwner(t_Handle                   h_ReplicGroup,
631                                bool                       add)
632{
633    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
634    ASSERT_COND(p_ReplicGroup);
635
636    /* update the group owner counter */
637    if (add)
638        p_ReplicGroup->owners++;
639    else
640    {
641        ASSERT_COND(p_ReplicGroup->owners);
642        p_ReplicGroup->owners--;
643    }
644}
645
646t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup)
647{
648    t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
649
650    ASSERT_COND(h_ReplicGroup);
651
652    if (FmPcdLockTryLock(p_ReplicGroup->p_Lock))
653        return E_OK;
654
655    return ERROR_CODE(E_BUSY);
656}
657
658void FrmReplicGroupUnlock(t_Handle h_ReplicGroup)
659{
660    t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
661
662    ASSERT_COND(h_ReplicGroup);
663
664    FmPcdLockUnlock(p_ReplicGroup->p_Lock);
665}
666/*********************** End of inter-module routines ************************/
667
668
669/****************************************/
670/*       API Init unit functions        */
671/****************************************/
672t_Handle FM_PCD_FrmReplicSetGroup(t_Handle                    h_FmPcd,
673                                  t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)
674{
675    t_FmPcdFrmReplicGroup       *p_ReplicGroup;
676    t_FmPcdFrmReplicMember      *p_CurrentMember, *p_NextMember = NULL;
677    int                         i;
678    t_Error                     err;
679    bool                        last = FALSE;
680    t_Handle                    h_Muram;
681
682    SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);
683    SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL);
684
685    if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd))
686    {
687        REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));
688        return NULL;
689    }
690
691    err = CheckParams(h_FmPcd, p_ReplicGroupParam);
692    if (err)
693    {
694        REPORT_ERROR(MAJOR, err, (NO_MSG));
695        return NULL;
696    }
697
698    p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup));
699    if (!p_ReplicGroup)
700    {
701        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));
702        return NULL;
703    }
704    memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup));
705
706    /* initialize lists for internal driver use */
707    INIT_LIST(&p_ReplicGroup->availableMembersList);
708    INIT_LIST(&p_ReplicGroup->membersList);
709
710    p_ReplicGroup->h_FmPcd = h_FmPcd;
711
712    h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);
713    ASSERT_COND(h_Muram);
714
715    /* initialize the group lock */
716    p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd);
717    if (!p_ReplicGroup->p_Lock)
718    {
719        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock"));
720        DeleteGroup(p_ReplicGroup);
721        return NULL;
722    }
723
724    /* Allocate the frame replicator source table descriptor */
725    p_ReplicGroup->p_SourceTd =
726        (t_Handle)FM_MURAM_AllocMem(h_Muram,
727                                    FM_PCD_CC_AD_ENTRY_SIZE,
728                                    FM_PCD_CC_AD_TABLE_ALIGN);
729    if (!p_ReplicGroup->p_SourceTd)
730    {
731        REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor"));
732        DeleteGroup(p_ReplicGroup);
733        return NULL;
734    }
735
736    /* update the shadow size - required for the host commands */
737    err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd,
738                              FM_PCD_CC_AD_ENTRY_SIZE,
739                              FM_PCD_CC_AD_TABLE_ALIGN);
740    if (err)
741    {
742        REPORT_ERROR(MAJOR, err, ("Update CC shadow"));
743        DeleteGroup(p_ReplicGroup);
744        return NULL;
745    }
746
747    p_ReplicGroup->maxNumOfEntries  = p_ReplicGroupParam->maxNumOfEntries;
748
749    /* Allocate the maximal number of members ADs and Statistics AD for the group
750       It prevents allocation of Muram in run-time */
751    for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)
752    {
753        err = AllocMember(p_ReplicGroup);
754        if (err)
755        {
756            REPORT_ERROR(MAJOR, err, ("allocate a new member"));
757            DeleteGroup(p_ReplicGroup);
758            return NULL;
759        }
760    }
761
762    /* Initialize the members linked lists:
763      (hw - the one that is used by the FMan controller and
764       sw - the one that is managed by the driver internally) */
765    for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--)
766    {
767        /* check if this is the last member in the group */
768        if (i == (p_ReplicGroupParam->numOfEntries-1))
769            last = TRUE;
770        else
771            last = FALSE;
772
773        /* Initialize a new member */
774        p_CurrentMember = InitMember(p_ReplicGroup,
775                                     &(p_ReplicGroupParam->nextEngineParams[i]),
776                                     last);
777        if (!p_CurrentMember)
778        {
779            REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
780            DeleteGroup(p_ReplicGroup);
781            return NULL;
782        }
783
784        /* Build the members group - link two consecutive members in the hw linked list */
785        LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember);
786
787        /* update the driver internal members list to be compatible to the hw members linked list */
788        AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList);
789
790        p_NextMember = p_CurrentMember;
791    }
792
793    /* initialize the source table descriptor */
794    BuildSourceTd(p_ReplicGroup->p_SourceTd);
795
796    /* link the source table descriptor to point to the first member in the group */
797    LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember);
798
799    return p_ReplicGroup;
800}
801
802t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup)
803{
804    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;
805
806    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
807
808    if (p_ReplicGroup->owners)
809        RETURN_ERROR(MAJOR,
810                     E_INVALID_STATE,
811                     ("the group has owners and can't be deleted"));
812
813    DeleteGroup(p_ReplicGroup);
814
815    return E_OK;
816}
817
818
819/*****************************************************************************/
820/*       API Run-time Frame replicator Control unit functions                */
821/*****************************************************************************/
822t_Error FM_PCD_FrmReplicAddMember(t_Handle                  h_ReplicGroup,
823                                  uint16_t                  memberIndex,
824                                  t_FmPcdCcNextEngineParams *p_MemberParams)
825{
826    t_FmPcdFrmReplicGroup       *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
827    t_FmPcdFrmReplicMember      *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL;
828    t_Error                     err;
829    uint8_t                     memberPosition;
830
831    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
832    SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE);
833
834    /* group lock */
835    err = FrmReplicGroupTryLock(p_ReplicGroup);
836    if (GET_ERROR_TYPE(err) == E_BUSY)
837        return ERROR_CODE(E_BUSY);
838
839    if (memberIndex > p_ReplicGroup->numOfEntries)
840    {
841        /* unlock */
842        FrmReplicGroupUnlock(p_ReplicGroup);
843        RETURN_ERROR(MAJOR, E_INVALID_SELECTION,
844                     ("memberIndex is greater than the members in the list"));
845    }
846
847    if (memberIndex >= p_ReplicGroup->maxNumOfEntries)
848    {
849        /* unlock */
850        FrmReplicGroupUnlock(p_ReplicGroup);
851        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group"));
852    }
853
854    if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)
855    {
856        /* unlock */
857        FrmReplicGroupUnlock(p_ReplicGroup);
858        RETURN_ERROR(MAJOR, E_INVALID_VALUE,
859                     ("numOfEntries with new entry can not be larger than %d\n",
860                      FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));
861    }
862
863    err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams);
864    if (err)
865    {
866        /* unlock */
867        FrmReplicGroupUnlock(p_ReplicGroup);
868        RETURN_ERROR(MAJOR, err, ("member check parameters in add operation"));
869    }
870    /* determine the member position in the group */
871    memberPosition = GetMemberPosition(p_ReplicGroup,
872                                       memberIndex,
873                                       TRUE/* add operation */);
874
875    /* Initialize a new member */
876    p_NewMember = InitMember(p_ReplicGroup,
877                             p_MemberParams,
878                             (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE));
879    if (!p_NewMember)
880    {
881        /* unlock */
882        FrmReplicGroupUnlock(p_ReplicGroup);
883        RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));
884    }
885
886    switch (memberPosition)
887    {
888        case FRM_REPLIC_FIRST_MEMBER_INDEX:
889            p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
890            ASSERT_COND(p_CurrentMember);
891
892            LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
893
894            /* update the internal group source TD */
895            LinkSourceToMember(p_ReplicGroup,
896                               p_ReplicGroup->p_SourceTd,
897                               p_NewMember);
898
899            /* add member to the internal sw member list */
900            AddMemberToList(p_ReplicGroup,
901                            p_NewMember,
902                            &p_ReplicGroup->membersList);
903            break;
904
905        case FRM_REPLIC_MIDDLE_MEMBER_INDEX:
906            p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);
907            ASSERT_COND(p_CurrentMember);
908
909            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
910            ASSERT_COND(p_PreviousMember);
911
912            LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);
913            LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
914
915            AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
916            break;
917
918        case FRM_REPLIC_LAST_MEMBER_INDEX:
919            p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));
920            ASSERT_COND(p_PreviousMember);
921
922            LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);
923            FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/);
924
925            /* add the new member to the internal sw member list */
926            AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);
927           break;
928
929        default:
930            /* unlock */
931            FrmReplicGroupUnlock(p_ReplicGroup);
932            RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member"));
933
934    }
935
936    /* unlock */
937    FrmReplicGroupUnlock(p_ReplicGroup);
938
939    return E_OK;
940}
941
942t_Error FM_PCD_FrmReplicRemoveMember(t_Handle   h_ReplicGroup,
943                                     uint16_t   memberIndex)
944{
945    t_FmPcdFrmReplicGroup   *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;
946    t_Error                 err;
947
948    SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);
949
950    /* lock */
951    err = FrmReplicGroupTryLock(p_ReplicGroup);
952    if (GET_ERROR_TYPE(err) == E_BUSY)
953        return ERROR_CODE(E_BUSY);
954
955    if (memberIndex >= p_ReplicGroup->numOfEntries)
956        RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove"));
957
958    /* Design decision: group must contain at least one member
959       No possibility to remove the last member from the group */
960    if (p_ReplicGroup->numOfEntries == 1)
961        RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group."));
962
963    err = RemoveMember(p_ReplicGroup, memberIndex);
964
965    /* unlock */
966    FrmReplicGroupUnlock(p_ReplicGroup);
967
968    switch (GET_ERROR_TYPE(err))
969    {
970        case E_OK:
971            return E_OK;
972
973        case E_BUSY:
974            DBG(TRACE, ("E_BUSY error"));
975            return ERROR_CODE(E_BUSY);
976
977        default:
978            RETURN_ERROR(MAJOR, err, NO_MSG);
979    }
980}
981
982/*********************** End of API routines ************************/
983
984
985