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