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 /****************************************/
GetMemberPosition(t_FmPcdFrmReplicGroup * p_ReplicGroup,uint32_t memberIndex,bool isAddOperation)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
MemberCheckParams(t_Handle h_FmPcd,t_FmPcdCcNextEngineParams * p_MemberParams)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
CheckParams(t_Handle h_FmPcd,t_FmPcdFrmReplicGroupParams * p_ReplicGroupParam)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
GetAvailableMember(t_FmPcdFrmReplicGroup * p_ReplicGroup)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
PutAvailableMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_ReplicMember)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
AddMemberToList(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_CurrentMember,t_List * p_ListHead)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
RemoveMemberFromList(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_CurrentMember)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
LinkSourceToMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_AdOfTypeContLookup * p_SourceTd,t_FmPcdFrmReplicMember * p_ReplicMember)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
LinkMemberToMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_CurrentMember,t_FmPcdFrmReplicMember * p_NextMember)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
ModifyDescriptor(t_FmPcdFrmReplicGroup * p_ReplicGroup,void * p_OldDescriptor,void * p_NewDescriptor)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
FillReplicAdOfTypeResult(void * p_ReplicAd,bool last)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
BuildSourceTd(void * p_Ad)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
BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_NextMember,t_FmPcdFrmReplicMember * p_CurrentMember,bool sourceDescriptor,bool last)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
GetMemberByIndex(t_FmPcdFrmReplicGroup * p_ReplicGroup,uint16_t memberIndex)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
AllocMember(t_FmPcdFrmReplicGroup * p_ReplicGroup)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
InitMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdCcNextEngineParams * p_MemberParams,bool last)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
FreeMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,t_FmPcdFrmReplicMember * p_Member)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
RemoveMember(t_FmPcdFrmReplicGroup * p_ReplicGroup,uint16_t memberIndex)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
DeleteGroup(t_FmPcdFrmReplicGroup * p_ReplicGroup)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 */
FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup)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
FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup,void * p_Ad,t_Handle * h_AdNew)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
FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup,bool add)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
FrmReplicGroupTryLock(t_Handle h_ReplicGroup)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
FrmReplicGroupUnlock(t_Handle h_ReplicGroup)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 /****************************************/
FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd,t_FmPcdFrmReplicGroupParams * p_ReplicGroupParam)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
FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup)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 /*****************************************************************************/
FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup,uint16_t memberIndex,t_FmPcdCcNextEngineParams * p_MemberParams)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
FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup,uint16_t memberIndex)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