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 /****************************************/
55 static 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 
94 static 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 
113 static 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 
140 static 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 
155 static void PutAvailableMember(t_FmPcdFrmReplicGroup    *p_ReplicGroup,
156                                t_FmPcdFrmReplicMember   *p_ReplicMember)
157 {
158     LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList);
159 }
160 
161 static 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 
170 static 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 
178 static 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 
197 static 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 
219 static 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 
246 static 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 
265 static 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 
280 static 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 
342 static 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 
361 static 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 
396 static 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 
434 static 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 
448 static 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 
530 static 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 */
604 void * 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 
612 void 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 
630 void  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 
646 t_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 
658 void 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 /****************************************/
672 t_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 
802 t_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 /*****************************************************************************/
822 t_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 
942 t_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