oam.c (100304B)
1 /* 2 * 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 */ 8 9 #include <sal/core/libc.h> 10 #include <shared/bsl.h> 11 #include <soc/defs.h> 12 #include <soc/drv.h> 13 #include <soc/scache.h> 14 #include <soc/profile_mem.h> 15 #include <soc/hash.h> 16 #include <soc/l3x.h> 17 #include <soc/triumph2.h> 18 19 #include <bcm/l3.h> 20 #include <bcm/oam.h> 21 22 #include <bcm_int/esw/oam.h> 23 #include <bcm_int/esw/port.h> 24 #include <bcm_int/esw/l3.h> 25 #include <bcm_int/esw/switch.h> 26 #include <bcm_int/esw/stack.h> 27 #include <bcm_int/esw/triumph2.h> 28 29 #include <bcm_int/esw_dispatch.h> 30 31 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_APOLLO_SUPPORT) || \ 32 defined(BCM_VALKYRIE2_SUPPORT) 33 34 #define LEVEL_BIT_COUNT 3 35 #define LEVEL_COUNT (1 << (LEVEL_BIT_COUNT)) 36 #define MAX_ENDPOINT_LEVEL (LEVEL_COUNT - 1) 37 #define MANGLED_GROUP_NAME_LENGTH (BCM_OAM_GROUP_NAME_LENGTH) 38 39 #define UNSUPPORTED_ENDPOINT_FLAGS \ 40 (BCM_OAM_ENDPOINT_LOSS_MEASUREMENT) 41 42 #define CHECK_INIT \ 43 if (!oam_info_p->initialized) \ 44 { \ 45 return BCM_E_INIT; \ 46 } 47 48 #define SET_OAM_INFO oam_info_p = &oam_info[unit]; 49 50 #define SET_GROUP(_group_index_) group_p = \ 51 oam_info_p->groups + _group_index_; 52 53 #define SET_ENDPOINT(_endpoint_index_) endpoint_p = \ 54 oam_info_p->endpoints + _endpoint_index_; 55 56 #define VALIDATE_GROUP_INDEX(_group_index_) \ 57 if ((_group_index_) < 0 || (_group_index_) >= oam_info_p->group_count) \ 58 { \ 59 return BCM_E_PARAM; \ 60 } \ 61 62 #define VALIDATE_ENDPOINT_INDEX(_endpoint_index_) \ 63 if ((_endpoint_index_) < 0 || \ 64 (_endpoint_index_) >= oam_info_p->endpoint_count) \ 65 { \ 66 return BCM_E_PARAM; \ 67 } \ 68 69 70 static _bcm_oam_info_t oam_info[BCM_MAX_NUM_UNITS]; 71 72 static _bcm_oam_fault_t group_faults[] = 73 { 74 {CURRENT_XCON_CCM_DEFECTf, STICKY_XCON_CCM_DEFECTf, 75 BCM_OAM_GROUP_FAULT_CCM_XCON, 0x08}, 76 77 {CURRENT_ERROR_CCM_DEFECTf, STICKY_ERROR_CCM_DEFECTf, 78 BCM_OAM_GROUP_FAULT_CCM_ERROR, 0x04}, 79 80 {CURRENT_SOME_RMEP_CCM_DEFECTf, STICKY_SOME_RMEP_CCM_DEFECTf, 81 BCM_OAM_GROUP_FAULT_CCM_TIMEOUT, 0x02}, 82 83 {CURRENT_SOME_RDI_DEFECTf, STICKY_SOME_RDI_DEFECTf, 84 BCM_OAM_GROUP_FAULT_REMOTE, 0x01}, 85 86 {0, 0, 0, 0} 87 }; 88 89 static _bcm_oam_fault_t endpoint_faults[] = 90 { 91 {CURRENT_RMEP_PORT_STATUS_DEFECTf, STICKY_RMEP_PORT_STATUS_DEFECTf, 92 BCM_OAM_ENDPOINT_FAULT_PORT_DOWN, 0x08}, 93 94 {CURRENT_RMEP_INTERFACE_STATUS_DEFECTf, 95 STICKY_RMEP_INTERFACE_STATUS_DEFECTf, 96 BCM_OAM_ENDPOINT_FAULT_INTERFACE_DOWN, 0x04}, 97 98 {CURRENT_RMEP_CCM_DEFECTf, STICKY_RMEP_CCM_DEFECTf, 99 BCM_OAM_ENDPOINT_FAULT_CCM_TIMEOUT, 0x20}, 100 101 {CURRENT_RMEP_LAST_RDIf, STICKY_RMEP_LAST_RDIf, 102 BCM_OAM_ENDPOINT_FAULT_REMOTE, 0x10}, 103 104 {0, 0, 0, 0} 105 }; 106 107 static _bcm_oam_interrupt_t interrupts[] = 108 { 109 {ANY_RMEP_TLV_PORT_DOWN_STATUSr, FIRST_RMEP_INDEXf, INVALIDf, 110 ANY_RMEP_TLV_PORT_DOWN_INTRf, bcmOAMEventEndpointPortDown}, 111 112 {ANY_RMEP_TLV_PORT_UP_STATUSr, FIRST_RMEP_INDEXf, INVALIDf, 113 ANY_RMEP_TLV_PORT_UP_INTRf, bcmOAMEventEndpointPortUp}, 114 115 {ANY_RMEP_TLV_INTERFACE_DOWN_STATUSr, FIRST_RMEP_INDEXf, INVALIDf, 116 ANY_RMEP_TLV_INTERFACE_DOWN_INTRf, bcmOAMEventEndpointInterfaceDown}, 117 118 {ANY_RMEP_TLV_INTERFACE_UP_STATUSr, FIRST_RMEP_INDEXf, INVALIDf, 119 ANY_RMEP_TLV_INTERFACE_UP_INTRf, bcmOAMEventEndpointInterfaceUp}, 120 121 {XCON_CCM_DEFECT_STATUSr, INVALIDf, FIRST_MA_INDEXf, 122 ERROR_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMxcon}, 123 124 {ERROR_CCM_DEFECT_STATUSr, INVALIDf, FIRST_MA_INDEXf, 125 ERROR_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMError}, 126 127 {SOME_RDI_DEFECT_STATUSr, FIRST_RMEP_INDEXf, FIRST_MA_INDEXf, 128 SOME_RDI_DEFECT_INTRf, bcmOAMEventGroupRemote}, 129 130 {SOME_RMEP_CCM_DEFECT_STATUSr, FIRST_RMEP_INDEXf, FIRST_MA_INDEXf, 131 SOME_RMEP_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMTimeout}, 132 133 {INVALIDr, INVALIDf, 0} 134 }; 135 136 static soc_field_t interrupt_enable_fields[bcmOAMEventCount] = 137 { 138 /* This must be in the same order as the bcm_oam_event_type_t enum */ 139 140 ANY_RMEP_TLV_PORT_DOWN_INT_ENABLEf, 141 ANY_RMEP_TLV_PORT_UP_INT_ENABLEf, 142 ANY_RMEP_TLV_INTERFACE_DOWN_INT_ENABLEf, 143 ANY_RMEP_TLV_INTERFACE_UP_INT_ENABLEf, 144 INVALIDf, 145 INVALIDf, 146 INVALIDf, 147 INVALIDf, 148 INVALIDf, 149 INVALIDf, 150 INVALIDf, 151 INVALIDf, 152 INVALIDf, 153 INVALIDf, 154 XCON_CCM_DEFECT_INT_ENABLEf, 155 ERROR_CCM_DEFECT_INT_ENABLEf, 156 SOME_RDI_DEFECT_INT_ENABLEf, 157 SOME_RMEP_CCM_DEFECT_INT_ENABLEf, 158 INVALIDf, 159 }; 160 161 static uint32 ccm_periods[] = 162 { 163 BCM_OAM_ENDPOINT_CCM_PERIOD_DISABLED, 164 BCM_OAM_ENDPOINT_CCM_PERIOD_3MS, 165 BCM_OAM_ENDPOINT_CCM_PERIOD_10MS, 166 BCM_OAM_ENDPOINT_CCM_PERIOD_100MS, 167 BCM_OAM_ENDPOINT_CCM_PERIOD_1S, 168 BCM_OAM_ENDPOINT_CCM_PERIOD_10S, 169 BCM_OAM_ENDPOINT_CCM_PERIOD_1M, 170 BCM_OAM_ENDPOINT_CCM_PERIOD_10M, 171 _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED 172 }; 173 174 static void *_bcm_tr2x_oam_alloc_clear(unsigned int size, char *description) 175 { 176 void *block_p; 177 178 block_p = sal_alloc(size, description); 179 180 if (block_p != NULL) 181 { 182 sal_memset(block_p, 0, size); 183 } 184 185 return block_p; 186 } 187 188 static int _bcm_tr2x_oam_quantize_ccm_period(int period) 189 { 190 int quantized_period; 191 192 if (period == 0) { 193 quantized_period = 0; 194 } 195 else { 196 /* Find closest supported period */ 197 for (quantized_period = 1; 198 ccm_periods[quantized_period] != 199 _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED; ++quantized_period) { 200 if (period < ccm_periods[quantized_period]) { 201 break; 202 } 203 } 204 205 if (quantized_period > 1) { 206 if (ccm_periods[quantized_period] == 207 _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED) { 208 /* Use the highest defined value */ 209 --quantized_period; 210 } 211 else { 212 if (period - ccm_periods[quantized_period - 1] < 213 ccm_periods[quantized_period] - period) { 214 /* Closer to the lower value */ 215 --quantized_period; 216 } 217 } 218 } 219 } 220 221 return quantized_period; 222 } 223 224 /* 225 * Function: 226 * _bcm_tr2x_oam_clear_rmep 227 * Purpose: 228 * Delete RMEP entry or Install fresh RMEP entry in the Hardware, clearing 229 * the faults. 230 * 231 * Parameters: 232 * unit - (IN) BCM device number 233 * h_data_p - (IN) Pointer to Endpoint info associated with RMEP entry 234 * being cleared. 235 * valid - (IN) 0 => Delete the H/w entry 236 * 1 => Install fresh entry with faults cleared. 237 * Returns: 238 * BCM_E_XXX 239 */ 240 STATIC int 241 _bcm_tr2x_oam_clear_rmep (int unit, _bcm_oam_endpoint_t *endpoints, int valid) 242 { 243 244 rmep_entry_t rmep_entry; /* RMEP table entry. */ 245 int rv = BCM_E_INTERNAL; /* Operation return status entry */ 246 uint32 oam_cur_time; /* Current time in H/w state machine */ 247 248 if (endpoints == NULL) { 249 LOG_ERROR(BSL_LS_BCM_OAM, 250 (BSL_META_U(unit, 251 "OAM ERR: Arg h_data_p NULL check failed\n"))); 252 return BCM_E_INTERNAL; 253 } 254 255 LOG_VERBOSE(BSL_LS_BCM_OAM, 256 (BSL_META_U(unit, 257 "OAM, EP id %d, valid %d\n"), 258 endpoints->remote_index, valid)); 259 260 /* RMEP table programming. */ 261 sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t)); 262 263 /* if valid==0 delete RMEP entry, else create a clean RMEP entry */ 264 if (!(valid)) { 265 rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, endpoints->remote_index, 266 &rmep_entry); 267 if (rv != BCM_E_NONE) { 268 LOG_ERROR(BSL_LS_BCM_OAM, 269 (BSL_META_U(unit, 270 "OAM ERR: Deleting RMEP entry failied\n"))); 271 } 272 return rv; 273 } 274 275 /* Set the MA group index. */ 276 soc_RMEPm_field32_set(unit, &rmep_entry, MAID_INDEXf, 277 endpoints->group_index); 278 279 /* 280 * The following steps are necessary to enable CCM timeout events 281 * without having received any CCMs. 282 */ 283 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMP_VALIDf, 1); 284 285 BCM_IF_ERROR_RETURN(READ_OAM_CURRENT_TIMEr(unit, &oam_cur_time)); 286 287 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMPf, oam_cur_time); 288 289 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_RECEIVED_CCMf, 290 _bcm_tr2x_oam_quantize_ccm_period(endpoints->period)); 291 /* End of timeout setup */ 292 293 294 soc_RMEPm_field32_set(unit, &rmep_entry, VALIDf, 1); 295 296 rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, endpoints->remote_index, 297 &rmep_entry); 298 if (rv != BCM_E_NONE) { 299 LOG_ERROR(BSL_LS_BCM_OAM, 300 (BSL_META_U(unit, 301 "OAM ERR: Clearing RMEP entry failied\n"))); 302 return (rv); 303 } 304 305 return BCM_E_NONE; 306 } 307 308 /* 309 * Function: 310 * _bcm_tr2x_oam_clear_ma_state 311 * Purpose: 312 * Delete MA_STATE entry or Install fresh MA_STATE entry in the Hardware, 313 * Clearing the faults. 314 * Parameters: 315 * unit - (IN) BCM device number 316 * group_info - (IN) Group info associated with MA_STATE entry being 317 * cleared. 318 * index - (IN) H/w index of MA_STATE entry to be modified. 319 * valid - (IN) 0 => Delete the H/w entry 320 * 1 => Install fresh entry with faults cleared. 321 * Returns: 322 * BCM_E_XXX 323 */ 324 STATIC int 325 _bcm_tr2x_oam_clear_ma_state(int unit, _bcm_oam_group_t *group_info, 326 int index, int valid) 327 { 328 329 ma_state_entry_t ma_state_entry; /* MA State table entry. */ 330 331 LOG_VERBOSE(BSL_LS_BCM_OAM, 332 (BSL_META_U(unit, 333 "OAM *group_info %p, index %d, valid %d\n"), 334 group_info, index, valid)); 335 336 if (group_info == NULL) { 337 LOG_ERROR(BSL_LS_BCM_OAM, 338 (BSL_META_U(unit, 339 "OAM ERR: Arg group_info NULL check failed\n"))); 340 return BCM_E_INTERNAL; 341 } 342 343 sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t)); 344 345 /* Mark the entry as valid. */ 346 soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, valid); 347 348 /* Set the lowest alarm priority info. */ 349 if (valid) { 350 soc_MA_STATEm_field32_set(unit, &ma_state_entry, LOWESTALARMPRIf, 351 group_info->lowest_alarm_priority); 352 } 353 354 /* Write group information to hardware table. */ 355 SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, index, 356 &ma_state_entry)); 357 return BCM_E_NONE; 358 } 359 360 /* 361 * Function: 362 * _bcm_tr2x_oam_group_recreate 363 * Purpose: 364 * Recreate MA_STATE and RMEP entries, due to current H/w limitation 365 * Currently there is a race condition between H/w and Software 366 * When RMEP is deleted and if it has any faults then, 367 * MA_STATE remote fault counters need to be decremented by software. 368 * However it may so happen that after reading RMEP faults and just 369 * before RMEP deletion, the fault gets cleared and H/w already decremented 370 * the MA_STATE table, now when software decrements the MA_STATE it would 371 * get MA_STATE table into an inconsistent state. 372 * As a solution we always recreate the entire group on a RMEP deletion. 373 * Parameters: 374 * unit - (IN) BCM device number 375 * group_id - (IN) Group Index, 376 * as per current implementation this is same as MA_STATE index. 377 * Returns: 378 * BCM_E_XXX 379 * Expects: 380 * OAM LOCK 381 */ 382 STATIC int 383 _bcm_tr2x_oam_group_recreate(int unit, int index) 384 { 385 _bcm_oam_info_t *oam_info_p = NULL; 386 _bcm_oam_group_t *group_p = NULL; 387 _bcm_oam_endpoint_t *endpoint_p = NULL; 388 int rv = BCM_E_NONE; 389 bcm_oam_endpoint_t endpoint_index; 390 391 SET_OAM_INFO; 392 393 CHECK_INIT; 394 395 SET_GROUP(index); 396 /*if unused Group, just clear the MA_STATE index, including the valid bit*/ 397 if (!(group_p->in_use)) { 398 LOG_WARN(BSL_LS_BCM_OAM, 399 (BSL_META_U(unit, 400 "OAM, WARN: Recieved group recreate request for " 401 "unused Group Id %d\n"), index)); 402 403 rv = _bcm_tr2x_oam_clear_ma_state(unit, group_p, index, 0); 404 if (BCM_FAILURE(rv)) { 405 LOG_ERROR(BSL_LS_BCM_OAM, 406 (BSL_META_U(unit, 407 "OAM Error: MA_STATE clear failed group id %d - " 408 "%s.\n"), index, bcm_errmsg(rv))); 409 } 410 411 return rv; 412 } 413 414 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 415 ++endpoint_index) { 416 SET_ENDPOINT(endpoint_index); 417 if (endpoint_p->in_use && endpoint_p->group_index == index) { 418 rv = _bcm_tr2x_oam_clear_rmep(unit, endpoint_p, 0); 419 if (BCM_FAILURE(rv)) { 420 LOG_ERROR(BSL_LS_BCM_OAM, 421 (BSL_META_U(unit, 422 "OAM Error: RMEP clear failed EP id %d - " 423 "%s.\n"), index, bcm_errmsg(rv))); 424 } 425 } 426 } 427 428 rv = _bcm_tr2x_oam_clear_ma_state(unit, group_p, index, 1); 429 if (BCM_FAILURE(rv)) { 430 LOG_ERROR(BSL_LS_BCM_OAM, 431 (BSL_META_U(unit, 432 "OAM Error: MA_STATE clear failed group id %d - " 433 "%s.\n"), index, bcm_errmsg(rv))); 434 return rv; 435 } 436 437 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 438 ++endpoint_index) { 439 SET_ENDPOINT(endpoint_index); 440 if (endpoint_p->in_use && endpoint_p->group_index == index) { 441 rv = _bcm_tr2x_oam_clear_rmep(unit, endpoint_p, 1); 442 if (BCM_FAILURE(rv)) { 443 LOG_ERROR(BSL_LS_BCM_OAM, 444 (BSL_META_U(unit, 445 "OAM Error: RMEP clear failed EP id %d - " 446 "%s.\n"), index, bcm_errmsg(rv))); 447 } 448 } 449 } 450 451 return rv; 452 } 453 454 STATIC int 455 _bcm_tr2x_oam_ser_handler(int unit, soc_mem_t mem, int index) 456 { 457 int rv = BCM_E_NONE; 458 bcm_oam_endpoint_t remote_ep_index; 459 _bcm_oam_info_t *oam_info_p = NULL; 460 _bcm_oam_endpoint_t *endpoints = NULL; 461 rmep_entry_t rmep_entry; 462 463 SET_OAM_INFO; 464 465 CHECK_INIT; 466 467 LOG_VERBOSE(BSL_LS_BCM_OAM, 468 (BSL_META_U(unit, 469 "OAM SER on mem %s, index %d\n"), 470 SOC_MEM_NAME(unit, mem), index)); 471 472 switch(mem){ 473 case MA_STATEm: 474 VALIDATE_GROUP_INDEX(index); 475 BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit)); 476 rv = _bcm_tr2x_oam_group_recreate(unit, index); 477 bcm_esw_oam_unlock(unit); 478 break; 479 480 case RMEPm: 481 VALIDATE_ENDPOINT_INDEX(index); 482 BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit)); 483 484 /* Get the logical index from H/w RMEP index */ 485 remote_ep_index = oam_info_p->remote_endpoints[index]; 486 if(remote_ep_index == BCM_OAM_ENDPOINT_INVALID) { 487 /* clean the HW RMEP index */ 488 sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t)); 489 rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, index, 490 &rmep_entry); 491 bcm_esw_oam_unlock(unit); 492 break; 493 } 494 /* Get handle to Hash data */ 495 endpoints = &(oam_info_p->endpoints[remote_ep_index]); 496 497 if (!(endpoints->in_use)) { 498 /* If endpoint not in use, just clear the RMEP entry in memory */ 499 LOG_WARN(BSL_LS_BCM_OAM, 500 (BSL_META_U(unit, 501 "OAM, WARN: Recieved Parity Error on" 502 "unused Remote Id %d\n"), remote_ep_index)); 503 /* Just clear this entry including valid bit */ 504 rv = _bcm_tr2x_oam_clear_rmep(unit, endpoints, 0); 505 } else { 506 /* Get the group Id from EP data, call group recreate routine */ 507 rv = _bcm_tr2x_oam_group_recreate(unit, endpoints->group_index); 508 } 509 510 bcm_esw_oam_unlock(unit); 511 break; 512 513 default: 514 LOG_ERROR(BSL_LS_BCM_OAM, 515 (BSL_META_U(unit, 516 "OAM, ERR: Invalid mem in OAM SER correction " 517 "routine %s\n"), SOC_MEM_NAME(unit, mem))); 518 bcm_esw_oam_unlock(unit); 519 520 return BCM_E_INTERNAL; 521 } 522 523 LOG_VERBOSE(BSL_LS_BCM_OAM, 524 (BSL_META_U(unit, 525 "OAM SER completed on mem %s, index %d, rv %d\n"), 526 SOC_MEM_NAME(unit, mem), index, rv)); 527 528 return rv; 529 530 } 531 532 static int _bcm_tr2x_oam_handle_interrupt(int unit, soc_field_t fault_field) 533 { 534 _bcm_oam_info_t *oam_info_p; 535 _bcm_oam_interrupt_t *interrupt_p; 536 uint32 interrupt_status; 537 bcm_oam_group_t group_index; 538 bcm_oam_endpoint_t endpoint_index; 539 _bcm_oam_event_handler_t *event_handler_p; 540 uint32 flags = 0; 541 542 SET_OAM_INFO; 543 544 CHECK_INIT; 545 546 BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit)); 547 548 for (interrupt_p = interrupts; 549 interrupt_p->status_register != INVALIDr; 550 ++interrupt_p) 551 { 552 if (BCM_FAILURE(soc_reg32_get(unit, interrupt_p->status_register, 553 REG_PORT_ANY, 0, &interrupt_status))) 554 { 555 continue; 556 } 557 558 if (soc_reg_field_get(unit, interrupt_p->status_register, 559 interrupt_status, VALIDf) && 560 oam_info_p->event_handler_count[interrupt_p->event_type] > 0) 561 { 562 group_index = (interrupt_p->group_index_field != INVALIDf) ? 563 soc_reg_field_get(unit, interrupt_p->status_register, 564 interrupt_status, interrupt_p->group_index_field) : 565 BCM_OAM_GROUP_INVALID; 566 567 endpoint_index = (interrupt_p->endpoint_index_field != INVALIDf) ? 568 soc_reg_field_get(unit, interrupt_p->status_register, 569 interrupt_status, interrupt_p->endpoint_index_field) : 570 BCM_OAM_ENDPOINT_INVALID; 571 572 if (endpoint_index != BCM_OAM_ENDPOINT_INVALID) 573 { 574 /* Find the logical endpoint for this RMEP */ 575 576 endpoint_index = oam_info_p->remote_endpoints[endpoint_index]; 577 } 578 579 flags = 0; 580 flags |= soc_reg_field_get(unit, interrupt_p->status_register, 581 interrupt_status, MULTIf) ? BCM_OAM_EVENT_FLAGS_MULTIPLE : 0; 582 583 for (event_handler_p = oam_info_p->event_handler_list_p; 584 event_handler_p != NULL; 585 event_handler_p = event_handler_p->next_p) 586 { 587 if (SHR_BITGET(event_handler_p->event_types.w, 588 interrupt_p->event_type)) 589 { 590 event_handler_p->cb(unit, flags, interrupt_p->event_type, 591 group_index, endpoint_index, 592 event_handler_p->user_data); 593 } 594 } 595 } 596 597 /* Clear interrupt */ 598 599 if (BCM_FAILURE(soc_reg32_set(unit, interrupt_p->status_register, 600 REG_PORT_ANY, 0, 0))) 601 { 602 continue; 603 } 604 } 605 606 return bcm_esw_oam_unlock(unit); 607 } 608 609 #ifdef BCM_WARM_BOOT_SUPPORT 610 611 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 612 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 613 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_1 614 615 STATIC 616 int _bcm_oam_warm_boot(int unit) 617 { 618 _bcm_oam_info_t *oam_info_p; 619 _bcm_oam_group_t *group_p; 620 int group_index; 621 maid_reduction_entry_t maid_reduction_entry; 622 ma_state_entry_t ma_state_entry; 623 int maid_reduction_valid; 624 int ma_state_valid; 625 _bcm_oam_endpoint_t *endpoint_p; 626 int l3_entry_count; 627 int l3_entry_index; 628 l3_entry_ipv4_unicast_entry_t l3_entry; 629 uint32 level_bitmap; 630 int level; 631 int lmep_index; 632 int stable_size; 633 int glp; 634 int epidx; 635 bcm_vlan_t vlan; 636 lmep_entry_t lmep_entry; 637 rmep_entry_t rmep_entry; 638 ma_index_entry_t ma_index_entry; 639 uint8 *group_names_p; 640 soc_scache_handle_t scache_handle; 641 uint16 recovered_ver; 642 uint32 alloc_size; 643 644 SET_OAM_INFO; 645 646 /* Calculate the scache memory required for OAM module */ 647 alloc_size = oam_info_p->group_count * (BCM_OAM_GROUP_NAME_LENGTH); 648 649 /* Get groups */ 650 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 651 if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) 652 && (stable_size > alloc_size)) { 653 654 /* Point scache_handle to OAM module */ 655 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0); 656 657 /* Get the OAM module base scache pointer value */ 658 BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 659 FALSE, alloc_size, &group_names_p, BCM_WB_DEFAULT_VERSION, 660 &recovered_ver)); 661 } 662 663 for (group_index = 0; group_index < oam_info_p->group_count; 664 ++group_index) 665 { 666 SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit, 667 MEM_BLOCK_ANY, group_index, &maid_reduction_entry)); 668 669 SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, group_index, 670 &ma_state_entry)); 671 672 maid_reduction_valid = soc_MAID_REDUCTIONm_field32_get(unit, 673 &maid_reduction_entry, VALIDf); 674 675 ma_state_valid = soc_MA_STATEm_field32_get(unit, 676 &ma_state_entry, VALIDf); 677 678 if (maid_reduction_valid || ma_state_valid) 679 { 680 if (!maid_reduction_valid || !ma_state_valid) 681 { 682 return BCM_E_INTERNAL; 683 } 684 685 SET_GROUP(group_index); 686 687 if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) || (stable_size == 0)) { 688 /* Return zeros as the name */ 689 sal_memset(group_p->name, 0, BCM_OAM_GROUP_NAME_LENGTH); 690 } else { 691 /* Use stored values */ 692 /* 693 * COVERITY 694 * group_names_p has been initilized in soc_scache_ptr_get 695 */ 696 /* coverity[uninit_use_in_call : FALSE] */ 697 sal_memcpy(group_p->name, group_names_p, BCM_OAM_GROUP_NAME_LENGTH); 698 group_names_p += BCM_OAM_GROUP_NAME_LENGTH; 699 } 700 group_p->in_use = 1; 701 } 702 } 703 704 /* Get endpoints */ 705 706 endpoint_p = oam_info_p->endpoints; 707 l3_entry_count = soc_mem_index_count(unit, L3_ENTRY_IPV4_UNICASTm); 708 709 for (l3_entry_index = 0; l3_entry_index < l3_entry_count; ++l3_entry_index) 710 { 711 SOC_IF_ERROR_RETURN(READ_L3_ENTRY_IPV4_UNICASTm(unit, MEM_BLOCK_ANY, 712 l3_entry_index, &l3_entry)); 713 714 if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, VALIDf)) 715 { 716 switch (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, KEY_TYPEf)) 717 { 718 case TR_L3_HASH_KEY_TYPE_RMEP: 719 endpoint_p->remote_index = 720 soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 721 RMEP__RMEP_PTRf); 722 723 SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY, 724 endpoint_p->remote_index, &rmep_entry)); 725 726 if (!soc_RMEPm_field32_get(unit, &rmep_entry, VALIDf)) 727 { 728 return BCM_E_INTERNAL; 729 } 730 731 endpoint_p->in_use = 1; 732 endpoint_p->is_remote = 1; 733 734 endpoint_p->group_index = soc_RMEPm_field32_get(unit, 735 &rmep_entry, MAID_INDEXf); 736 737 endpoint_p->name = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 738 &l3_entry, RMEP__MEPIDf); 739 740 endpoint_p->level = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 741 &l3_entry, RMEP__MDLf); 742 743 endpoint_p->vlan = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 744 &l3_entry, RMEP__VIDf); 745 746 endpoint_p->glp = soc_L3_ENTRY_IPV4_UNICASTm_field32_get 747 (unit, &l3_entry, RMEP__SGLPf); 748 749 SHR_BITSET(oam_info_p->remote_endpoints_in_use, 750 endpoint_p->remote_index); 751 752 ++endpoint_p; 753 754 break; 755 756 case TR_L3_HASH_KEY_TYPE_LMEP: 757 level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 758 &l3_entry, LMEP__MDL_BITMAPf); 759 760 for (level = 0; level < LEVEL_COUNT; ++level) 761 { 762 if (level_bitmap & (1 << level)) 763 { 764 /* There's an endpoint here at this level */ 765 766 endpoint_p->local_rx_index = 767 soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 768 &l3_entry, LMEP__MA_BASE_PTRf) << 769 LEVEL_BIT_COUNT | level; 770 771 SOC_IF_ERROR_RETURN(READ_MA_INDEXm(unit, 772 MEM_BLOCK_ANY, endpoint_p->local_rx_index, 773 &ma_index_entry)); 774 775 endpoint_p->in_use = 1; 776 endpoint_p->is_remote = 0; 777 endpoint_p->local_rx_enabled = 1; 778 779 endpoint_p->group_index = 780 soc_MA_INDEXm_field32_get(unit, 781 &ma_index_entry, MA_PTRf); 782 783 /* Name is not used for receive-only endpoints */ 784 endpoint_p->name = 0xffff; 785 786 endpoint_p->level = level; 787 788 endpoint_p->vlan = 789 soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 790 &l3_entry, LMEP__VIDf); 791 792 endpoint_p->glp = 793 soc_L3_ENTRY_IPV4_UNICASTm_field32_get 794 (unit, &l3_entry, LMEP__SGLPf); 795 796 SHR_BITSET(oam_info_p->local_rx_endpoints_in_use, 797 endpoint_p->local_rx_index); 798 799 ++endpoint_p; 800 } 801 } 802 803 break; 804 805 default: 806 continue; 807 } 808 } 809 } 810 811 for (lmep_index = 0; lmep_index < oam_info_p->local_tx_endpoint_count; 812 ++lmep_index) 813 { 814 SOC_IF_ERROR_RETURN(READ_LMEPm(unit, MEM_BLOCK_ANY, lmep_index, 815 &lmep_entry)); 816 817 group_index = soc_LMEPm_field32_get(unit, 818 &lmep_entry, MAID_INDEXf); 819 820 SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit, 821 MEM_BLOCK_ANY, group_index, &maid_reduction_entry)); 822 823 if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry, 824 VALIDf)) 825 { 826 glp = soc_LMEPm_field32_get(unit, &lmep_entry, DESTf); 827 vlan = soc_LMEPm_field32_get(unit, &lmep_entry, VLAN_IDf); 828 829 /* Check if a receive entry exists for this LMEP */ 830 831 for (epidx = 0; epidx < oam_info_p->endpoint_count; epidx++) 832 { 833 SET_ENDPOINT(epidx); 834 if (!endpoint_p->in_use) 835 { 836 continue; 837 } 838 if ((endpoint_p->vlan == vlan) && (endpoint_p->glp == glp) && 839 (endpoint_p->name == 0xffff)) 840 { 841 break; 842 } 843 } 844 if (epidx == oam_info_p->endpoint_count) 845 { 846 /* Receive entry not found - local TX only */ 847 /* Allocate a new ID */ 848 for (epidx = 0; epidx < oam_info_p->endpoint_count; epidx++) 849 { 850 SET_ENDPOINT(epidx); 851 if (!endpoint_p->in_use) 852 { 853 endpoint_p->glp = glp; 854 endpoint_p->vlan = vlan; 855 break; 856 } 857 } 858 } 859 860 endpoint_p->in_use = 1; 861 endpoint_p->is_remote = 0; 862 endpoint_p->local_tx_enabled = 1; 863 endpoint_p->local_tx_index = lmep_index; 864 endpoint_p->name = soc_LMEPm_field32_get(unit, &lmep_entry, 865 MEPIDf); 866 endpoint_p->level = soc_LMEPm_field32_get(unit, &lmep_entry, 867 MDLf); 868 endpoint_p->group_index = group_index; 869 870 SHR_BITSET(oam_info_p->local_tx_endpoints_in_use, lmep_index); 871 872 ++endpoint_p; 873 } 874 } 875 876 /* Upgrade case */ 877 if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) 878 && (stable_size > alloc_size) 879 && (recovered_ver < BCM_WB_VERSION_1_1)) { 880 881 /* Set scache_handle to OAM module */ 882 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0); 883 884 /* realloc to store max OAM group information */ 885 SOC_IF_ERROR_RETURN(soc_scache_realloc(unit, scache_handle, 886 alloc_size)); 887 } 888 889 return BCM_E_NONE; 890 } 891 /* 892 * Function: 893 * bcm_tr2x_oam_scache_alloc 894 * Purpose: 895 * Allocate memory for OAM module in scache 896 * Parameters: 897 * unit - (IN) Unit number. 898 * Returns: 899 * BCM_E_XXX 900 * Notes: 901 */ 902 STATIC int 903 bcm_tr2x_oam_scache_alloc(int unit) 904 { 905 _bcm_oam_info_t *oam_info_p; 906 soc_scache_handle_t scache_handle; 907 uint8 *oam_scache; 908 int alloc_sz = 0; 909 910 SET_OAM_INFO; 911 912 alloc_sz = BCM_OAM_GROUP_NAME_LENGTH * (oam_info_p->group_count); 913 914 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0); 915 BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 1, 916 alloc_sz, &oam_scache, BCM_WB_DEFAULT_VERSION, NULL)); 917 return BCM_E_NONE; 918 } 919 920 #endif /* BCM_WARM_BOOT_SUPPORT */ 921 922 static void _bcm_tr2x_oam_free_memory(_bcm_oam_info_t *oam_info_p) 923 { 924 sal_free(oam_info_p->remote_endpoints); 925 sal_free(oam_info_p->remote_endpoints_in_use); 926 sal_free(oam_info_p->local_rx_endpoints_in_use); 927 sal_free(oam_info_p->local_tx_endpoints_in_use); 928 sal_free(oam_info_p->endpoints); 929 sal_free(oam_info_p->groups); 930 } 931 932 static void _bcm_tr2x_oam_event_unregister_all(_bcm_oam_info_t *oam_info_p) 933 { 934 _bcm_oam_event_handler_t *event_handler_p; 935 _bcm_oam_event_handler_t *event_handler_to_delete_p; 936 937 event_handler_p = oam_info_p->event_handler_list_p; 938 939 while (event_handler_p != NULL) 940 { 941 event_handler_to_delete_p = event_handler_p; 942 event_handler_p = event_handler_p->next_p; 943 944 sal_free(event_handler_to_delete_p); 945 } 946 oam_info_p->event_handler_list_p = NULL; 947 } 948 949 /* 950 * Function: 951 * bcm_tr2x_oam_init 952 * Purpose: 953 * Initialize the OAM subsystem 954 * Parameters: 955 * unit - (IN) Unit number. 956 * Returns: 957 * BCM_E_XXX 958 * Notes: 959 */ 960 int 961 bcm_tr2x_oam_init( 962 int unit) 963 { 964 _bcm_oam_info_t *oam_info_p; 965 bcm_oam_endpoint_t endpoint_index; 966 bcm_port_t port_index; 967 uint32 register_value; 968 int result; 969 970 SET_OAM_INFO; 971 972 if (oam_info_p->initialized) 973 { 974 /* Reset everything */ 975 976 _bcm_tr2x_oam_event_unregister_all(oam_info_p); 977 978 BCM_IF_ERROR_RETURN(bcm_tr2x_oam_group_destroy_all(unit)); 979 _bcm_tr2x_oam_free_memory(oam_info_p); 980 } 981 982 oam_info_p->group_count = soc_mem_index_count(unit, MA_STATEm); 983 984 oam_info_p->groups = 985 _bcm_tr2x_oam_alloc_clear(oam_info_p->group_count * 986 sizeof(_bcm_oam_group_t), "_bcm_oam_group"); 987 988 if (oam_info_p->groups == NULL) 989 { 990 return BCM_E_MEMORY; 991 } 992 993 oam_info_p->remote_endpoint_count = soc_mem_index_count(unit, RMEPm); 994 oam_info_p->local_tx_endpoint_count = soc_mem_index_count(unit, LMEPm); 995 996 oam_info_p->local_rx_endpoint_count = 997 soc_mem_index_count(unit, MA_INDEXm); 998 999 oam_info_p->endpoint_count = oam_info_p->remote_endpoint_count + 1000 oam_info_p->local_tx_endpoint_count + 1001 oam_info_p->local_rx_endpoint_count; 1002 1003 oam_info_p->endpoints = 1004 _bcm_tr2x_oam_alloc_clear(oam_info_p->endpoint_count * 1005 sizeof(_bcm_oam_endpoint_t), "_bcm_oam_endpoint"); 1006 1007 if (oam_info_p->endpoints == NULL) 1008 { 1009 _bcm_tr2x_oam_free_memory(oam_info_p); 1010 1011 return BCM_E_MEMORY; 1012 } 1013 1014 oam_info_p->local_tx_endpoints_in_use = 1015 _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p-> 1016 local_tx_endpoint_count), 1017 "local_tx_endpoints_in_use"); 1018 1019 if (oam_info_p->local_tx_endpoints_in_use == NULL) 1020 { 1021 _bcm_tr2x_oam_free_memory(oam_info_p); 1022 1023 return BCM_E_MEMORY; 1024 } 1025 1026 oam_info_p->local_rx_endpoints_in_use = 1027 _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p-> 1028 local_rx_endpoint_count), 1029 "local_rx_endpoints_in_use"); 1030 1031 if (oam_info_p->local_rx_endpoints_in_use == NULL) 1032 { 1033 _bcm_tr2x_oam_free_memory(oam_info_p); 1034 1035 return BCM_E_MEMORY; 1036 } 1037 1038 oam_info_p->remote_endpoints_in_use = 1039 _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p-> 1040 remote_endpoint_count), 1041 "remote_endpoints_in_use"); 1042 1043 if (oam_info_p->remote_endpoints_in_use == NULL) 1044 { 1045 _bcm_tr2x_oam_free_memory(oam_info_p); 1046 1047 return BCM_E_MEMORY; 1048 } 1049 1050 oam_info_p->remote_endpoints = 1051 sal_alloc(oam_info_p->remote_endpoint_count * 1052 sizeof(bcm_oam_endpoint_t), "rmep reverse lookup"); 1053 1054 if (oam_info_p->remote_endpoints == NULL) 1055 { 1056 _bcm_tr2x_oam_free_memory(oam_info_p); 1057 1058 return BCM_E_MEMORY; 1059 } 1060 1061 for (endpoint_index = 0; 1062 endpoint_index < oam_info_p->remote_endpoint_count; 1063 ++endpoint_index) 1064 { 1065 oam_info_p->remote_endpoints[endpoint_index] = 1066 BCM_OAM_ENDPOINT_INVALID; 1067 } 1068 1069 soc_triumph2_oam_handler_register(unit, _bcm_tr2x_oam_handle_interrupt); 1070 soc_triumph2_oam_ser_handler_register(unit, _bcm_tr2x_oam_ser_handler); 1071 1072 #ifdef BCM_WARM_BOOT_SUPPORT 1073 if (!SOC_WARM_BOOT(unit)) { 1074 bcm_tr2x_oam_scache_alloc(unit); 1075 } 1076 if (SOC_WARM_BOOT(unit)) 1077 { 1078 result = _bcm_oam_warm_boot(unit); 1079 if (BCM_FAILURE(result)) { 1080 soc_triumph2_oam_handler_register(unit, NULL); 1081 _bcm_tr2x_oam_free_memory(oam_info_p); 1082 return (BCM_E_INTERNAL); 1083 } 1084 } 1085 else 1086 #endif /* BCM_WARM_BOOT_SUPPORT */ 1087 { 1088 /* Enable OAM message reception on all ports */ 1089 1090 PBMP_ALL_ITER(unit, port_index) 1091 { 1092 result = bcm_esw_port_control_set(unit, port_index, 1093 bcmPortControlOAMEnable, 1); 1094 if (BCM_FAILURE(result)) { 1095 soc_triumph2_oam_handler_register(unit, NULL); 1096 soc_triumph2_oam_ser_handler_register(unit, NULL); 1097 _bcm_tr2x_oam_free_memory(oam_info_p); 1098 return (result); 1099 } 1100 1101 } 1102 1103 /* Enable CCM reception timeouts */ 1104 1105 register_value = 0; 1106 1107 soc_reg_field_set(unit, OAM_TIMER_CONTROLr, ®ister_value, 1108 TIMER_ENABLEf, 1); 1109 1110 soc_reg_field_set(unit, OAM_TIMER_CONTROLr, ®ister_value, 1111 CLK_GRANf, 1); 1112 1113 result = WRITE_OAM_TIMER_CONTROLr(unit, register_value); 1114 1115 if (SOC_FAILURE(result)) 1116 { 1117 _bcm_tr2x_oam_free_memory(oam_info_p); 1118 1119 return result; 1120 } 1121 1122 /* Common information for outgoing CCM packets */ 1123 1124 result = WRITE_LMEP_COMMON_1r(unit, _BCM_OAM_MAC_DA_UPPER_32); 1125 1126 if (SOC_FAILURE(result)) 1127 { 1128 _bcm_tr2x_oam_free_memory(oam_info_p); 1129 1130 return result; 1131 } 1132 1133 /* Enable CCM transmission */ 1134 1135 register_value = 0; 1136 1137 soc_reg_field_set(unit, OAM_TX_CONTROLr, ®ister_value, 1138 TX_ENABLEf, 1); 1139 1140 soc_reg_field_set(unit, OAM_TX_CONTROLr, ®ister_value, 1141 CMIC_BUF_ENABLEf, 1); 1142 1143 result = WRITE_OAM_TX_CONTROLr(unit, register_value); 1144 1145 if (SOC_FAILURE(result)) 1146 { 1147 _bcm_tr2x_oam_free_memory(oam_info_p); 1148 1149 return result; 1150 } 1151 1152 register_value = 0; 1153 1154 soc_reg_field_set(unit, LMEP_COMMON_2r, ®ister_value, 1155 DA_15_3f, _BCM_OAM_MAC_DA_LOWER_13 >> 3); 1156 1157 soc_reg_field_set(unit, LMEP_COMMON_2r, ®ister_value, 1158 L3f, 1); 1159 1160 result = WRITE_LMEP_COMMON_2r(unit, register_value); 1161 1162 if (SOC_FAILURE(result)) 1163 { 1164 _bcm_tr2x_oam_free_memory(oam_info_p); 1165 1166 return result; 1167 } 1168 } 1169 1170 oam_info_p->initialized = 1; 1171 1172 return BCM_E_NONE; 1173 } 1174 1175 /* 1176 * Function: 1177 * bcm_tr2x_oam_detach 1178 * Purpose: 1179 * Shut down the OAM subsystem 1180 * Parameters: 1181 * unit - (IN) Unit number. 1182 * Returns: 1183 * BCM_E_XXX 1184 * Notes: 1185 */ 1186 int 1187 bcm_tr2x_oam_detach( 1188 int unit) 1189 { 1190 _bcm_oam_info_t *oam_info_p; 1191 bcm_port_t port_index; 1192 1193 SET_OAM_INFO; 1194 1195 if (!oam_info_p->initialized) 1196 { 1197 return BCM_E_NONE; 1198 } 1199 1200 /* Disable CCM transmission */ 1201 1202 SOC_IF_ERROR_RETURN(WRITE_OAM_TX_CONTROLr(unit, 0)); 1203 1204 /* Disable OAM message reception on all ports */ 1205 1206 PBMP_ALL_ITER(unit, port_index) 1207 { 1208 BCM_IF_ERROR_RETURN(bcm_esw_port_control_set(unit, 1209 port_index, bcmPortControlOAMEnable, 0)); 1210 } 1211 1212 soc_triumph2_oam_handler_register(unit, NULL); 1213 1214 _bcm_tr2x_oam_event_unregister_all(oam_info_p); 1215 1216 _bcm_tr2x_oam_free_memory(oam_info_p); 1217 1218 oam_info_p->initialized = 0; 1219 1220 return BCM_E_NONE; 1221 } 1222 1223 static void _bcm_tr2x_oam_group_name_mangle(uint8 *name_p, 1224 uint8 *mangled_name_p) 1225 { 1226 uint8 *byte_p = name_p + BCM_OAM_GROUP_NAME_LENGTH - 1; 1227 int bytes_left = BCM_OAM_GROUP_NAME_LENGTH; 1228 1229 while (bytes_left > 0) 1230 { 1231 *mangled_name_p = *byte_p; 1232 1233 ++mangled_name_p; 1234 --byte_p; 1235 --bytes_left; 1236 } 1237 } 1238 1239 /* 1240 * Function: 1241 * bcm_tr2x_oam_group_create 1242 * Purpose: 1243 * Create or replace an OAM group object 1244 * Parameters: 1245 * unit - (IN) Unit number. 1246 * group_info - (IN/OUT) Pointer to an OAM group structure 1247 * Returns: 1248 * BCM_E_XXX 1249 * Notes: 1250 */ 1251 int 1252 bcm_tr2x_oam_group_create( 1253 int unit, 1254 bcm_oam_group_info_t *group_info) 1255 { 1256 _bcm_oam_info_t *oam_info_p; 1257 _bcm_oam_group_t *group_p; 1258 int replace; 1259 int group_index; 1260 int copy_to_cpu = 0; 1261 maid_reduction_entry_t maid_reduction_entry; 1262 ma_state_entry_t ma_state_entry; 1263 uint8 mangled_group_name[MANGLED_GROUP_NAME_LENGTH]; 1264 1265 SET_OAM_INFO; 1266 1267 CHECK_INIT; 1268 1269 replace = group_info->flags & BCM_OAM_GROUP_REPLACE; 1270 1271 if (group_info->flags & BCM_OAM_GROUP_WITH_ID) 1272 { 1273 group_index = group_info->id; 1274 1275 VALIDATE_GROUP_INDEX(group_index); 1276 1277 if (!replace && (oam_info_p->groups[group_index].in_use)) 1278 { 1279 return BCM_E_EXISTS; 1280 } 1281 } 1282 else 1283 { 1284 if (replace) 1285 { 1286 return BCM_E_PARAM; 1287 } 1288 1289 for (group_index = 0; group_index < oam_info_p->group_count; 1290 ++group_index) 1291 { 1292 if (!oam_info_p->groups[group_index].in_use) 1293 { 1294 break; 1295 } 1296 } 1297 1298 if (group_index >= oam_info_p->group_count) 1299 { 1300 return BCM_E_FULL; 1301 } 1302 1303 group_info->id = group_index; 1304 } 1305 1306 SET_GROUP(group_index); 1307 1308 sal_memcpy(group_p->name, group_info->name, BCM_OAM_GROUP_NAME_LENGTH); 1309 /* Store Lowest Alarm Priority */ 1310 group_p->lowest_alarm_priority = group_info->lowest_alarm_priority; 1311 1312 /* MAID_REDUCTION entry */ 1313 1314 _bcm_tr2x_oam_group_name_mangle(group_p->name, mangled_group_name); 1315 1316 sal_memset(&maid_reduction_entry, 0, sizeof(maid_reduction_entry_t)); 1317 1318 soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, REDUCED_MAIDf, 1319 soc_draco_crc32(mangled_group_name, MANGLED_GROUP_NAME_LENGTH)); 1320 1321 soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, SW_RDIf, 1322 (group_info->flags & BCM_OAM_GROUP_REMOTE_DEFECT_TX) ? 1 : 0); 1323 1324 copy_to_cpu = ((group_info->flags & BCM_OAM_GROUP_COPY_TO_CPU) ? 1 : 0); 1325 soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, 1326 COPY_TO_CPUf, copy_to_cpu); 1327 1328 soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, VALIDf, 1); 1329 1330 1331 1332 SOC_IF_ERROR_RETURN(WRITE_MAID_REDUCTIONm(unit, MEM_BLOCK_ALL, 1333 group_index, &maid_reduction_entry)); 1334 1335 /* MA_STATE entry */ 1336 1337 sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t)); 1338 1339 if (replace) { 1340 /* Keep defect status if group is being replaced */ 1341 SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ALL, group_index, 1342 &ma_state_entry)); 1343 } 1344 1345 soc_MA_STATEm_field32_set(unit, &ma_state_entry, LOWESTALARMPRIf, 1346 group_info->lowest_alarm_priority); 1347 1348 soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, 1); 1349 1350 SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, group_index, 1351 &ma_state_entry)); 1352 1353 /* Local control block */ 1354 1355 group_p->in_use = 1; 1356 1357 #ifdef BCM_WARM_BOOT_SUPPORT 1358 SOC_CONTROL_LOCK(unit); 1359 SOC_CONTROL(unit)->scache_dirty = 1; 1360 SOC_CONTROL_UNLOCK(unit); 1361 #endif 1362 1363 return BCM_E_NONE; 1364 } 1365 1366 static int _bcm_tr2x_oam_read_clear_faults(int unit, int entry_index, 1367 _bcm_oam_fault_t *faults, soc_mem_t mem, uint32 *entry_p, 1368 uint32 *fault_bits_p, uint32 *persistent_fault_bits_p, 1369 uint32 clear_persistent_fault_bits) 1370 { 1371 _bcm_oam_fault_t *fault_p; 1372 uint32 ccm_read_control_reg_value = 0; 1373 1374 for (fault_p = faults; fault_p->mask != 0; ++fault_p) 1375 { 1376 /* Current fault state */ 1377 1378 if (soc_mem_field32_get(unit, mem, entry_p, 1379 fault_p->current_field) != 0) 1380 { 1381 *fault_bits_p |= fault_p->mask; 1382 } 1383 1384 /* Sticky fault state */ 1385 1386 if (soc_mem_field32_get(unit, mem, entry_p, 1387 fault_p->sticky_field) != 0) 1388 { 1389 *persistent_fault_bits_p |= fault_p->mask; 1390 1391 /* Clear persistent faults if requested */ 1392 1393 if (clear_persistent_fault_bits & fault_p->mask) 1394 { 1395 soc_reg_field_set(unit, CCM_READ_CONTROLr, 1396 &ccm_read_control_reg_value, BITS_TO_CLEARf, 1397 fault_p->clear_sticky_mask); 1398 } 1399 } 1400 } 1401 1402 /* If any clear bits were set, do the clear now */ 1403 1404 if (ccm_read_control_reg_value != 0) 1405 { 1406 soc_reg_field_set(unit, CCM_READ_CONTROLr, 1407 &ccm_read_control_reg_value, ENABLE_CLEARf, 1); 1408 1409 /* 1410 * MA_STATE table, MEMORYf should be 0. 1411 */ 1412 if (mem == MA_STATEm) { 1413 soc_reg_field_set(unit, CCM_READ_CONTROLr, 1414 &ccm_read_control_reg_value, MEMORYf, 0); 1415 } else { 1416 soc_reg_field_set(unit, CCM_READ_CONTROLr, 1417 &ccm_read_control_reg_value, MEMORYf, 1); 1418 } 1419 1420 soc_reg_field_set(unit, CCM_READ_CONTROLr, 1421 &ccm_read_control_reg_value, INDEXf, entry_index); 1422 1423 SOC_IF_ERROR_RETURN(WRITE_CCM_READ_CONTROLr(unit, 1424 ccm_read_control_reg_value)); 1425 } 1426 1427 return BCM_E_NONE; 1428 } 1429 1430 static int _bcm_tr2x_oam_get_group(int unit, int group_index, 1431 _bcm_oam_group_t *group_p, bcm_oam_group_info_t *group_info) 1432 { 1433 maid_reduction_entry_t maid_reduction_entry; 1434 ma_state_entry_t ma_state_entry; 1435 1436 group_info->id = group_index; 1437 1438 if (!(group_info->flags & BCM_OAM_GROUP_GET_FAULTS_ONLY)) { 1439 sal_memcpy(group_info->name, group_p->name, BCM_OAM_GROUP_NAME_LENGTH); 1440 1441 /* MAID_REDUCTION entry */ 1442 1443 SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit, MEM_BLOCK_ANY, group_index, 1444 &maid_reduction_entry)); 1445 1446 if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry, 1447 SW_RDIf) != 0) 1448 { 1449 group_info->flags |= BCM_OAM_GROUP_REMOTE_DEFECT_TX; 1450 } 1451 1452 if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry, 1453 COPY_TO_CPUf) != 0) 1454 { 1455 group_info->flags |= BCM_OAM_GROUP_COPY_TO_CPU; 1456 } 1457 } else { 1458 group_info->flags &= ~BCM_OAM_GROUP_GET_FAULTS_ONLY; 1459 } 1460 /* MA_STATE entry */ 1461 1462 SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, group_index, 1463 &ma_state_entry)); 1464 1465 /* Get the Lowest Alarm Priority value*/ 1466 group_info->lowest_alarm_priority = 1467 soc_MA_STATEm_field32_get(unit, &ma_state_entry, LOWESTALARMPRIf); 1468 1469 return _bcm_tr2x_oam_read_clear_faults(unit, group_index, group_faults, 1470 MA_STATEm, (uint32 *) &ma_state_entry, &group_info->faults, 1471 &group_info->persistent_faults, group_info->clear_persistent_faults); 1472 } 1473 1474 /* 1475 * Function: 1476 * bcm_tr2x_oam_group_get 1477 * Purpose: 1478 * Get an OAM group object 1479 * Parameters: 1480 * unit - (IN) Unit number. 1481 * group - (IN) The ID of the group object to get 1482 * group_info - (OUT) Pointer to an OAM group structure to receive the data 1483 * Returns: 1484 * BCM_E_XXX 1485 * Notes: 1486 */ 1487 int 1488 bcm_tr2x_oam_group_get( 1489 int unit, 1490 bcm_oam_group_t group, 1491 bcm_oam_group_info_t *group_info) 1492 { 1493 _bcm_oam_info_t *oam_info_p; 1494 _bcm_oam_group_t *group_p; 1495 1496 SET_OAM_INFO; 1497 1498 CHECK_INIT; 1499 1500 VALIDATE_GROUP_INDEX(group); 1501 1502 SET_GROUP(group); 1503 1504 if (!group_p->in_use) 1505 { 1506 return BCM_E_NOT_FOUND; 1507 } 1508 1509 return _bcm_tr2x_oam_get_group(unit, group, group_p, group_info); 1510 } 1511 1512 static int _bcm_tr2x_oam_destroy_group(int unit, int group_index, 1513 _bcm_oam_group_t *group_p) 1514 { 1515 maid_reduction_entry_t maid_reduction_entry; 1516 ma_state_entry_t ma_state_entry; 1517 1518 /* Remove all associated endpoints */ 1519 1520 bcm_tr2x_oam_endpoint_destroy_all(unit, group_index); 1521 1522 /* MAID_REDUCTION entry */ 1523 1524 soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, VALIDf, 0); 1525 1526 SOC_IF_ERROR_RETURN(WRITE_MAID_REDUCTIONm(unit, MEM_BLOCK_ALL, 1527 group_index, &maid_reduction_entry)); 1528 1529 /* MA_STATE entry */ 1530 1531 soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, 0); 1532 1533 SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, group_index, 1534 &ma_state_entry)); 1535 1536 group_p->in_use = 0; 1537 1538 #ifdef BCM_WARM_BOOT_SUPPORT 1539 SOC_CONTROL_LOCK(unit); 1540 SOC_CONTROL(unit)->scache_dirty = 1; 1541 SOC_CONTROL_UNLOCK(unit); 1542 #endif 1543 1544 return BCM_E_NONE; 1545 } 1546 1547 /* 1548 * Function: 1549 * bcm_tr2x_oam_group_destroy 1550 * Purpose: 1551 * Destroy an OAM group object. All OAM endpoints associated 1552 * with the group will also be destroyed. 1553 * Parameters: 1554 * unit - (IN) Unit number. 1555 * group - (IN) The ID of the OAM group object to destroy 1556 * Returns: 1557 * BCM_E_XXX 1558 * Notes: 1559 */ 1560 int 1561 bcm_tr2x_oam_group_destroy( 1562 int unit, 1563 bcm_oam_group_t group) 1564 { 1565 _bcm_oam_info_t *oam_info_p; 1566 _bcm_oam_group_t *group_p; 1567 1568 SET_OAM_INFO; 1569 1570 CHECK_INIT; 1571 1572 VALIDATE_GROUP_INDEX(group); 1573 1574 SET_GROUP(group); 1575 1576 if (!group_p->in_use) 1577 { 1578 return BCM_E_NOT_FOUND; 1579 } 1580 1581 return _bcm_tr2x_oam_destroy_group(unit, group, group_p); 1582 } 1583 1584 /* 1585 * Function: 1586 * bcm_tr2x_oam_group_destroy_all 1587 * Purpose: 1588 * Destroy all OAM group objects. All OAM endpoints will also be 1589 * destroyed. 1590 * Parameters: 1591 * unit - (IN) Unit number. 1592 * Returns: 1593 * BCM_E_XXX 1594 * Notes: 1595 */ 1596 int 1597 bcm_tr2x_oam_group_destroy_all( 1598 int unit) 1599 { 1600 _bcm_oam_info_t *oam_info_p; 1601 _bcm_oam_group_t *group_p; 1602 int group_index; 1603 1604 SET_OAM_INFO; 1605 1606 CHECK_INIT; 1607 1608 for (group_index = 0; group_index < oam_info_p->group_count; 1609 ++group_index) 1610 { 1611 SET_GROUP(group_index); 1612 1613 if (group_p->in_use) 1614 { 1615 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_group(unit, group_index, 1616 group_p)); 1617 } 1618 } 1619 1620 return BCM_E_NONE; 1621 } 1622 1623 /* 1624 * Function: 1625 * bcm_tr2x_oam_group_traverse 1626 * Purpose: 1627 * Traverse the entire set of OAM groups, calling a specified 1628 * callback for each one 1629 * Parameters: 1630 * unit - (IN) Unit number. 1631 * cb - (IN) A pointer to the callback function to call for each OAM group 1632 * user_data - (IN) Pointer to user data to supply in the callback 1633 * Returns: 1634 * BCM_E_XXX 1635 * Notes: 1636 */ 1637 int 1638 bcm_tr2x_oam_group_traverse( 1639 int unit, 1640 bcm_oam_group_traverse_cb cb, 1641 void *user_data) 1642 { 1643 _bcm_oam_info_t *oam_info_p; 1644 _bcm_oam_group_t *group_p; 1645 int group_index; 1646 bcm_oam_group_info_t group_info; 1647 1648 SET_OAM_INFO; 1649 1650 CHECK_INIT; 1651 1652 if (cb == NULL) 1653 { 1654 return BCM_E_PARAM; 1655 } 1656 1657 for (group_index = 0; group_index < oam_info_p->group_count; 1658 ++group_index) 1659 { 1660 SET_GROUP(group_index); 1661 1662 if (group_p->in_use) 1663 { 1664 bcm_oam_group_info_t_init(&group_info); 1665 1666 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_get_group(unit, group_index, 1667 group_p, &group_info)); 1668 1669 BCM_IF_ERROR_RETURN(cb(unit, &group_info, user_data)); 1670 } 1671 } 1672 1673 return BCM_E_NONE; 1674 } 1675 1676 static int _bcm_tr2x_oam_find_free_endpoint(SHR_BITDCL *endpoints, 1677 int endpoint_count, int increment, int offset) 1678 { 1679 int endpoint_index; 1680 1681 for (endpoint_index = 0; endpoint_index < endpoint_count; 1682 endpoint_index += increment) 1683 { 1684 if (!SHR_BITGET(endpoints, endpoint_index + offset)) 1685 { 1686 break; 1687 } 1688 } 1689 1690 if (endpoint_index >= endpoint_count) 1691 { 1692 endpoint_index = _BCM_OAM_INVALID_INDEX; 1693 } 1694 1695 return endpoint_index + offset; 1696 } 1697 1698 static void _bcm_tr2x_oam_make_rmep_key(int unit, 1699 l3_entry_ipv4_unicast_entry_t *l3_key_p, uint16 name, int level, bcm_vlan_t vlan, 1700 uint32 sglp) 1701 { 1702 sal_memset(l3_key_p, 0, sizeof(l3_entry_ipv4_unicast_entry_t)); 1703 1704 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__MEPIDf, name); 1705 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__MDLf, level); 1706 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__VIDf, vlan); 1707 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__SGLPf, sglp); 1708 1709 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, KEY_TYPEf, 1710 TR_L3_HASH_KEY_TYPE_RMEP); 1711 } 1712 1713 static int _bcm_tr2x_oam_delete_rmep(int unit, _bcm_oam_endpoint_t *endpoint_p) 1714 { 1715 _bcm_oam_info_t *oam_info_p; 1716 l3_entry_ipv4_unicast_entry_t l3_key; 1717 rmep_entry_t rmep_entry; 1718 ma_state_entry_t ma_state_entry; 1719 int some_rmep_ccm_defect_counter = 0; 1720 int current_some_rmep_ccm_defect = 0; 1721 int some_rdi_defect_counter = 0; 1722 int current_some_rdi_defect = 0; 1723 int cur_rmep_ccm_defect = 0; 1724 int cur_rmep_last_rdi = 0; 1725 1726 SET_OAM_INFO; 1727 1728 sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t)); 1729 sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t)); 1730 SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY, endpoint_p->remote_index, 1731 &rmep_entry)); 1732 1733 cur_rmep_ccm_defect = soc_RMEPm_field32_get(unit, &rmep_entry, 1734 CURRENT_RMEP_CCM_DEFECTf); 1735 cur_rmep_last_rdi = soc_RMEPm_field32_get(unit, &rmep_entry, 1736 CURRENT_RMEP_LAST_RDIf); 1737 1738 if (cur_rmep_ccm_defect || cur_rmep_last_rdi) { 1739 SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, 1740 endpoint_p->group_index, 1741 &ma_state_entry)); 1742 1743 some_rmep_ccm_defect_counter = soc_MA_STATEm_field32_get(unit, 1744 &ma_state_entry, 1745 SOME_RMEP_CCM_DEFECT_COUNTERf); 1746 current_some_rmep_ccm_defect = soc_MA_STATEm_field32_get(unit, 1747 &ma_state_entry, 1748 CURRENT_SOME_RMEP_CCM_DEFECTf); 1749 1750 if (cur_rmep_ccm_defect && some_rmep_ccm_defect_counter > 0) { 1751 --some_rmep_ccm_defect_counter; 1752 soc_MA_STATEm_field32_set(unit, &ma_state_entry, 1753 SOME_RMEP_CCM_DEFECT_COUNTERf, 1754 some_rmep_ccm_defect_counter); 1755 1756 if (some_rmep_ccm_defect_counter == 0) { 1757 current_some_rmep_ccm_defect = 0; 1758 soc_MA_STATEm_field32_set(unit, &ma_state_entry, 1759 CURRENT_SOME_RMEP_CCM_DEFECTf, 1760 current_some_rmep_ccm_defect); 1761 } 1762 } 1763 some_rdi_defect_counter = soc_MA_STATEm_field32_get(unit, 1764 &ma_state_entry, 1765 SOME_RDI_DEFECT_COUNTERf); 1766 current_some_rdi_defect = soc_MA_STATEm_field32_get(unit, 1767 &ma_state_entry, 1768 CURRENT_SOME_RDI_DEFECTf); 1769 if (cur_rmep_last_rdi && some_rdi_defect_counter > 0) { 1770 --some_rdi_defect_counter; 1771 soc_MA_STATEm_field32_set(unit, &ma_state_entry, 1772 SOME_RDI_DEFECT_COUNTERf, 1773 some_rdi_defect_counter); 1774 if (some_rdi_defect_counter == 0) { 1775 current_some_rdi_defect = 0; 1776 soc_MA_STATEm_field32_set(unit, &ma_state_entry, 1777 CURRENT_SOME_RDI_DEFECTf, 1778 current_some_rdi_defect); 1779 } 1780 } 1781 1782 SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, 1783 endpoint_p->group_index, 1784 &ma_state_entry)); 1785 } 1786 1787 /* RMEP entry */ 1788 1789 SOC_IF_ERROR_RETURN( 1790 soc_mem_field32_modify(unit, RMEPm, endpoint_p->remote_index, VALIDf, 0)); 1791 1792 /* L3 entry */ 1793 1794 _bcm_tr2x_oam_make_rmep_key(unit, &l3_key, endpoint_p->name, 1795 endpoint_p->level, endpoint_p->vlan, endpoint_p->glp); 1796 1797 SOC_IF_ERROR_RETURN(soc_mem_delete(unit, L3_ENTRY_IPV4_UNICASTm, 1798 MEM_BLOCK_ALL, &l3_key)); 1799 1800 /* Local control block */ 1801 1802 SHR_BITCLR(oam_info_p->remote_endpoints_in_use, endpoint_p->remote_index); 1803 1804 oam_info_p->remote_endpoints[endpoint_p->remote_index] = 1805 BCM_OAM_ENDPOINT_INVALID; 1806 1807 return BCM_E_NONE; 1808 } 1809 1810 static int _bcm_tr2x_oam_find_lmep(int unit, bcm_vlan_t vlan, uint32 sglp, 1811 int *index_p, l3_entry_ipv4_unicast_entry_t *l3_entry_p) 1812 { 1813 l3_entry_ipv4_unicast_entry_t l3_key; 1814 1815 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, LMEP__VIDf, vlan); 1816 1817 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, LMEP__SGLPf, sglp); 1818 1819 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, KEY_TYPEf, 1820 TR_L3_HASH_KEY_TYPE_LMEP); 1821 1822 return soc_mem_search(unit, L3_ENTRY_IPV4_UNICASTm, MEM_BLOCK_ANY, 1823 index_p, &l3_key, l3_entry_p, 0); 1824 } 1825 1826 static int _bcm_tr2x_oam_find_free_local_endpoint_rx_index(int unit, 1827 SHR_BITDCL *endpoints, int endpoint_count, int increment, int offset, 1828 _bcm_oam_endpoint_t *endpoint_p) 1829 { 1830 int endpoint_index; 1831 int mdl_set = 0; 1832 int rv = BCM_E_NONE; 1833 int l3_index = 0; 1834 uint32 level_bitmap = 0; 1835 l3_entry_ipv4_unicast_entry_t l3_entry; 1836 1837 sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t)); 1838 1839 /* 1840 * Check if an entry already exists for this VLAN + GLP pair. 1841 */ 1842 L3_LOCK(unit); 1843 rv = _bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan, endpoint_p->glp, 1844 &l3_index, &l3_entry); 1845 if (rv == BCM_E_NOT_FOUND) 1846 { 1847 /* 1848 * If Entry is NOT found, select a new MA_INDEX for this MDL. 1849 */ 1850 L3_UNLOCK(unit); 1851 for (endpoint_index = 0; endpoint_index < endpoint_count; 1852 endpoint_index += increment) 1853 { 1854 SHR_BITTEST_RANGE(endpoints, endpoint_index, increment, mdl_set); 1855 if (0 == mdl_set) 1856 { 1857 break; 1858 } 1859 } 1860 if (endpoint_index >= endpoint_count) 1861 { 1862 return BCM_E_FULL; 1863 } 1864 endpoint_p->local_rx_index = (endpoint_index + offset); 1865 return BCM_E_NONE; 1866 } else if (rv >= 0) { 1867 /* 1868 * If there is a MATCH, check if this MD level is available at this 1869 * index. If it's already occupied, report resource error. 1870 * Else this MD level is available at this index. 1871 */ 1872 L3_UNLOCK(unit); 1873 level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 1874 &l3_entry, LMEP__MDL_BITMAPf); 1875 level_bitmap &= (1 << offset); 1876 if (!level_bitmap) 1877 { 1878 endpoint_p->local_rx_index = 1879 ((soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 1880 LMEP__MA_BASE_PTRf) << 3) | offset); 1881 return BCM_E_NONE; 1882 } else { 1883 return BCM_E_RESOURCE; 1884 } 1885 } else { 1886 /* 1887 * L3_ENTRY_IPV4_UNICAST table search operation failed. 1888 */ 1889 L3_UNLOCK(unit); 1890 return rv; 1891 } 1892 return BCM_E_NONE; 1893 } 1894 1895 static int _bcm_tr2x_oam_delete_lmep(int unit, 1896 _bcm_oam_endpoint_t *endpoint_p) 1897 { 1898 _bcm_oam_info_t *oam_info_p; 1899 int l3_index; 1900 l3_entry_ipv4_unicast_entry_t l3_entry; 1901 uint32 level_bitmap; 1902 int result = SOC_E_NONE; 1903 lmep_entry_t lmep_entry; 1904 1905 SET_OAM_INFO; 1906 1907 if (endpoint_p->local_tx_enabled) 1908 { 1909 /* LMEP entry */ 1910 1911 sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t)); 1912 WRITE_LMEPm(unit, MEM_BLOCK_ALL, 1913 endpoint_p->local_tx_index, &lmep_entry); 1914 1915 /* Local control block */ 1916 1917 SHR_BITCLR(oam_info_p->local_tx_endpoints_in_use, 1918 endpoint_p->local_tx_index); 1919 } 1920 1921 if (endpoint_p->local_rx_enabled) 1922 { 1923 /* MA_INDEX entry doesn't need to be touched */ 1924 1925 /* L3 entry */ 1926 1927 L3_LOCK(unit); 1928 1929 if (BCM_SUCCESS(_bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan, 1930 endpoint_p->glp, &l3_index, &l3_entry))) 1931 { 1932 level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 1933 &l3_entry, LMEP__MDL_BITMAPf); 1934 1935 level_bitmap &= ~(1 << endpoint_p->level); 1936 1937 if (level_bitmap != 0) 1938 { 1939 /* Still endpoints here at other levels */ 1940 1941 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm, 1942 l3_index, LMEP__MDL_BITMAPf, level_bitmap); 1943 } 1944 else 1945 { 1946 /* No endpoints left here at any level */ 1947 1948 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm, 1949 l3_index, VALIDf, 0); 1950 } 1951 } 1952 1953 L3_UNLOCK(unit); 1954 1955 SOC_IF_ERROR_RETURN(result); 1956 1957 /* Local control block */ 1958 1959 SHR_BITCLR(oam_info_p->local_rx_endpoints_in_use, 1960 endpoint_p->local_rx_index); 1961 } 1962 1963 return BCM_E_NONE; 1964 } 1965 1966 static int _bcm_tr2x_oam_destroy_endpoint(int unit, 1967 _bcm_oam_endpoint_t *endpoint_p) 1968 { 1969 if (endpoint_p->is_remote) 1970 { 1971 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_delete_rmep(unit, endpoint_p)); 1972 } 1973 else 1974 { 1975 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_delete_lmep(unit, endpoint_p)); 1976 } 1977 1978 endpoint_p->in_use = 0; 1979 1980 return BCM_E_NONE; 1981 } 1982 1983 /* 1984 * Function: 1985 * bcm_tr2x_oam_endpoint_create 1986 * Purpose: 1987 * Create or replace an OAM endpoint object 1988 * Parameters: 1989 * unit - (IN) Unit number. 1990 * endpoint_info - (IN/OUT) Pointer to an OAM endpoint structure 1991 * Returns: 1992 * BCM_E_XXX 1993 * Notes: 1994 */ 1995 int 1996 bcm_tr2x_oam_endpoint_create( 1997 int unit, 1998 bcm_oam_endpoint_info_t *endpoint_info) 1999 { 2000 _bcm_oam_info_t *oam_info_p; 2001 _bcm_oam_group_t *group_p; 2002 _bcm_oam_endpoint_t *endpoint_p; 2003 int replace; 2004 int is_remote; 2005 int local_tx_enabled = 0; 2006 int local_rx_enabled = 0; 2007 int endpoint_index; 2008 bcm_module_t module_id; 2009 bcm_port_t port_id; 2010 bcm_trunk_t trunk_id; 2011 int local_id; 2012 rmep_entry_t rmep_entry; 2013 lmep_entry_t lmep_entry; 2014 ma_index_entry_t ma_index_entry; 2015 l3_entry_ipv4_unicast_entry_t l3_entry; 2016 int quantization_index; 2017 int l3_index; 2018 uint32 level_bitmap; 2019 int result = SOC_E_NONE; 2020 uint32 oam_current_time; 2021 int chk_ep_index = 0; 2022 int rv = BCM_E_NONE; 2023 uint32 src_glp = _BCM_OAM_INVALID_INDEX; 2024 uint32 dst_glp = _BCM_OAM_INVALID_INDEX; 2025 bcm_trunk_member_t *member_array = NULL; 2026 int member_count; 2027 bcm_gport_t member_gport; 2028 bcm_trunk_t tgid_out; 2029 int id_out; 2030 2031 SET_OAM_INFO; 2032 2033 CHECK_INIT; 2034 2035 VALIDATE_GROUP_INDEX(endpoint_info->group); 2036 2037 if (endpoint_info->level > MAX_ENDPOINT_LEVEL) 2038 { 2039 /* Exceeds supported MDL level 0 - 7. */ 2040 return BCM_E_PARAM; 2041 } 2042 2043 if (endpoint_info->flags & UNSUPPORTED_ENDPOINT_FLAGS) 2044 { 2045 /* Invalid endpoint flag bit/s set. */ 2046 return BCM_E_UNAVAIL; 2047 } 2048 2049 if (endpoint_info->type != bcmOAMEndpointTypeEthernet) 2050 { 2051 /* Device supports Ethernet OAM only. */ 2052 return BCM_E_UNAVAIL; 2053 } 2054 2055 /* Replace operation. */ 2056 replace = (endpoint_info->flags & BCM_OAM_ENDPOINT_REPLACE) ? 1 : 0; 2057 2058 if (endpoint_info->flags & BCM_OAM_ENDPOINT_REMOTE) 2059 { 2060 if (endpoint_info->flags & 2061 (BCM_OAM_ENDPOINT_CCM_RX | BCM_OAM_ENDPOINT_LOOPBACK | 2062 BCM_OAM_ENDPOINT_DELAY_MEASUREMENT | BCM_OAM_ENDPOINT_LINKTRACE | 2063 BCM_OAM_ENDPOINT_PORT_STATE_TX | 2064 BCM_OAM_ENDPOINT_INTERFACE_STATE_TX )) 2065 { 2066 /* Specified flags aren't valid for RMEPs */ 2067 2068 return BCM_E_PARAM; 2069 } 2070 2071 is_remote = 1; 2072 } 2073 else 2074 { 2075 /* Local */ 2076 2077 is_remote = 0; 2078 2079 local_tx_enabled = (endpoint_info->ccm_period != 2080 BCM_OAM_ENDPOINT_CCM_PERIOD_DISABLED); 2081 2082 local_rx_enabled = ((endpoint_info->flags & 2083 (BCM_OAM_ENDPOINT_CCM_RX | BCM_OAM_ENDPOINT_LOOPBACK | 2084 BCM_OAM_ENDPOINT_DELAY_MEASUREMENT | 2085 BCM_OAM_ENDPOINT_LINKTRACE)) != 0); 2086 } 2087 2088 if (endpoint_info->flags & BCM_OAM_ENDPOINT_WITH_ID) 2089 { 2090 endpoint_index = endpoint_info->id; 2091 2092 VALIDATE_ENDPOINT_INDEX(endpoint_index); 2093 2094 if (replace && (!oam_info_p->endpoints[endpoint_index].in_use)) 2095 { 2096 return BCM_E_NOT_FOUND; 2097 } 2098 else if (!replace && (oam_info_p->endpoints[endpoint_index].in_use)) 2099 { 2100 return BCM_E_EXISTS; 2101 } 2102 2103 /* 2104 * An MA_STATE/group entry is associated with one and only one LMEP 2105 * If an rx LMEP entry already existed for current group, return error 2106 */ 2107 for (chk_ep_index = 0; chk_ep_index < oam_info_p->endpoint_count; 2108 ++chk_ep_index) { 2109 if (!replace && oam_info_p->endpoints[chk_ep_index].in_use 2110 && !is_remote 2111 && (oam_info_p->endpoints[chk_ep_index].group_index 2112 == endpoint_info->group) 2113 && oam_info_p->endpoints[chk_ep_index].local_rx_enabled) { 2114 return BCM_E_RESOURCE; 2115 } 2116 } 2117 } 2118 else 2119 { 2120 if (replace) 2121 { 2122 /* Replace specified with no ID */ 2123 2124 return BCM_E_PARAM; 2125 } 2126 2127 /* 2128 * An MA_STATE/group entry is associated with one and only one LMEP 2129 * If an rx LMEP entry already existed for current group, return error 2130 */ 2131 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 2132 ++endpoint_index) { 2133 if (oam_info_p->endpoints[endpoint_index].in_use 2134 && !is_remote 2135 && (oam_info_p->endpoints[endpoint_index].group_index 2136 == endpoint_info->group) 2137 && oam_info_p->endpoints[endpoint_index].local_rx_enabled) { 2138 return BCM_E_RESOURCE; 2139 } 2140 } 2141 2142 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 2143 ++endpoint_index) 2144 { 2145 if (!oam_info_p->endpoints[endpoint_index].in_use) 2146 { 2147 break; 2148 } 2149 } 2150 2151 if (endpoint_index >= oam_info_p->endpoint_count) 2152 { 2153 return BCM_E_FULL; 2154 } 2155 2156 endpoint_info->id = endpoint_index; 2157 } 2158 2159 SET_ENDPOINT(endpoint_index); 2160 2161 SET_GROUP(endpoint_info->group); 2162 2163 if (!group_p->in_use) 2164 { 2165 /* Associating to a nonexistent group */ 2166 2167 return BCM_E_PARAM; 2168 } 2169 2170 /* Get Trunk ID or (Modid + Port) value from Gport */ 2171 BCM_IF_ERROR_RETURN 2172 (_bcm_esw_gport_resolve(unit, endpoint_info->gport, &module_id, 2173 &port_id, &trunk_id, &local_id)); 2174 2175 /* 2176 * If Gport is Trunk type, _bcm_esw_gport_resolve() 2177 * sets trunk_id. Using Trunk ID, get Dst Modid and Port value. 2178 */ 2179 if (BCM_GPORT_IS_TRUNK(endpoint_info->gport)) { 2180 2181 if (BCM_TRUNK_INVALID == trunk_id) { 2182 /* Has to be a valid Trunk. */ 2183 return (BCM_E_PARAM); 2184 } 2185 2186 /* 2187 * CCM Tx is enabled on a trunk member port. 2188 * trunk_index value is required to derive the Modid and Port info. 2189 */ 2190 if (1 == local_tx_enabled 2191 && _BCM_OAM_INVALID_INDEX == endpoint_info->trunk_index) { 2192 /* Invalid Trunk member index passed. */ 2193 return (BCM_E_PORT); 2194 } 2195 2196 /* Get Trunk Info for the Trunk ID. */ 2197 BCM_IF_ERROR_RETURN 2198 (bcm_esw_trunk_get(unit, trunk_id, NULL, 0, NULL, &member_count)); 2199 if (0 == member_count) { 2200 /* No members have been added to the trunk group yet */ 2201 return BCM_E_PARAM; 2202 } 2203 member_array = sal_alloc(sizeof(bcm_trunk_member_t) * member_count, 2204 "trunk member array"); 2205 if (NULL == member_array) { 2206 return BCM_E_MEMORY; 2207 } 2208 rv = bcm_esw_trunk_get(unit, trunk_id, NULL, 2209 member_count, member_array, &member_count); 2210 if (BCM_FAILURE(rv)) { 2211 sal_free(member_array); 2212 return rv; 2213 } 2214 2215 /* Get the Modid and Port value using Trunk Index value. */ 2216 if (endpoint_info->trunk_index >= member_count) { 2217 sal_free(member_array); 2218 return BCM_E_PARAM; 2219 } 2220 member_gport = member_array[endpoint_info->trunk_index].gport; 2221 sal_free(member_array); 2222 BCM_IF_ERROR_RETURN 2223 (_bcm_esw_gport_resolve(unit, member_gport, &module_id, &port_id, 2224 &tgid_out, &id_out)); 2225 if ((-1 != tgid_out) || (-1 != id_out)) { 2226 return BCM_E_PARAM; 2227 } 2228 2229 /* Calculate the SGLP and DGLP values to program the MEP */ 2230 src_glp = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id); 2231 dst_glp = (module_id << 6) | port_id; 2232 } 2233 2234 /* 2235 * Application can resolve the trunk and pass the desginated 2236 * port as Gport value. Check if the Gport belongs to a trunk. 2237 */ 2238 if ((BCM_TRUNK_INVALID == trunk_id) 2239 && (BCM_GPORT_IS_MODPORT(endpoint_info->gport) 2240 || BCM_GPORT_IS_LOCAL(endpoint_info->gport))) { 2241 2242 /* When Gport is ModPort or Port type, _bcm_esw_gport_resolve() 2243 * returns Modid and Port value. Use these values to make the DGLP 2244 * value. 2245 */ 2246 dst_glp = ((module_id << 6) | port_id); 2247 2248 /* Use the Modid, Port value and determine if the port 2249 * belongs to a Trunk. 2250 */ 2251 rv = bcm_esw_trunk_find(unit, module_id, port_id, &trunk_id); 2252 if (BCM_SUCCESS(rv)) { 2253 /* 2254 * Port is member of a valid trunk. 2255 * Now create the SGLP value from Trunk ID. 2256 */ 2257 src_glp = (1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id; 2258 } else { 2259 /* Port not a member of trunk. DGLP and SGLP are the same. */ 2260 src_glp = dst_glp; 2261 } 2262 } 2263 2264 /* 2265 * At this point, both src_glp and dst_glp should be valid. 2266 * Gport types other than TRUNK, MODPORT or LOCAL are not valid. 2267 */ 2268 if (_BCM_OAM_INVALID_INDEX == src_glp 2269 || _BCM_OAM_INVALID_INDEX == dst_glp) { 2270 return (BCM_E_PORT); 2271 } 2272 2273 if (replace) 2274 { 2275 /* Remove anything being replaced from tables */ 2276 2277 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_endpoint(unit, endpoint_p)); 2278 } 2279 2280 quantization_index = _bcm_tr2x_oam_quantize_ccm_period 2281 (endpoint_info->ccm_period); 2282 2283 endpoint_p->is_remote = is_remote; 2284 endpoint_p->local_tx_enabled = local_tx_enabled; 2285 endpoint_p->local_rx_enabled = local_rx_enabled; 2286 endpoint_p->group_index = endpoint_info->group; 2287 endpoint_p->name = endpoint_info->name; 2288 endpoint_p->level = endpoint_info->level; 2289 endpoint_p->vlan = endpoint_info->vlan; 2290 endpoint_p->glp = src_glp; 2291 endpoint_p->period = endpoint_info->ccm_period; 2292 2293 if (is_remote) 2294 { 2295 endpoint_p->remote_index = 2296 _bcm_tr2x_oam_find_free_endpoint(oam_info_p-> 2297 remote_endpoints_in_use, 2298 oam_info_p->remote_endpoint_count, 1, 0); 2299 2300 if (endpoint_p->remote_index < 0) 2301 { 2302 return BCM_E_FULL; 2303 } 2304 2305 /* RMEP entry */ 2306 2307 sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t)); 2308 2309 soc_RMEPm_field32_set(unit, &rmep_entry, MAID_INDEXf, 2310 endpoint_info->group); 2311 2312 /* The following steps are necessary to enable CCM timeout events 2313 without having received any CCMs */ 2314 2315 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMP_VALIDf, 1); 2316 2317 BCM_IF_ERROR_RETURN(READ_OAM_CURRENT_TIMEr(unit, &oam_current_time)); 2318 2319 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMPf, 2320 oam_current_time); 2321 2322 soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_RECEIVED_CCMf, 2323 quantization_index); 2324 2325 /* End of timeout setup */ 2326 2327 soc_RMEPm_field32_set(unit, &rmep_entry, VALIDf, 1); 2328 2329 SOC_IF_ERROR_RETURN(WRITE_RMEPm(unit, MEM_BLOCK_ALL, 2330 endpoint_p->remote_index, &rmep_entry)); 2331 2332 /* L3 entry */ 2333 2334 sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t)); 2335 2336 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__CCMf, 2337 quantization_index); 2338 2339 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__RMEP_PTRf, 2340 endpoint_p->remote_index); 2341 2342 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__MEPIDf, 2343 endpoint_info->name); 2344 2345 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__MDLf, 2346 endpoint_info->level); 2347 2348 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__VIDf, 2349 endpoint_info->vlan); 2350 2351 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__SGLPf, 2352 src_glp); 2353 2354 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, KEY_TYPEf, 2355 TR_L3_HASH_KEY_TYPE_RMEP); 2356 2357 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, VALIDf, 1); 2358 2359 SOC_IF_ERROR_RETURN(soc_mem_insert(unit, L3_ENTRY_IPV4_UNICASTm, 2360 MEM_BLOCK_ALL, &l3_entry)); 2361 2362 /* Local control block */ 2363 2364 SHR_BITSET(oam_info_p->remote_endpoints_in_use, 2365 endpoint_p->remote_index); 2366 2367 oam_info_p->remote_endpoints[endpoint_p->remote_index] = 2368 endpoint_index; 2369 } 2370 else 2371 { 2372 if (local_tx_enabled) 2373 { 2374 uint32 reversed_maid[BCM_OAM_GROUP_NAME_LENGTH / 4]; 2375 int word_index; 2376 2377 endpoint_p->local_tx_index = 2378 _bcm_tr2x_oam_find_free_endpoint(oam_info_p-> 2379 local_tx_endpoints_in_use, 2380 oam_info_p->local_tx_endpoint_count, 1, 0); 2381 2382 if (endpoint_p->local_tx_index < 0) 2383 { 2384 return BCM_E_FULL; 2385 } 2386 2387 /* LMEP entry */ 2388 2389 sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t)); 2390 2391 soc_LMEPm_field32_set(unit, &lmep_entry, MAID_INDEXf, 2392 endpoint_info->group); 2393 2394 soc_LMEPm_mac_addr_set(unit, &lmep_entry, SAf, 2395 endpoint_info->src_mac_address); 2396 2397 soc_LMEPm_field32_set(unit, &lmep_entry, MDLf, endpoint_info->level); 2398 soc_LMEPm_field32_set(unit, &lmep_entry, MEPIDf, endpoint_info->name); 2399 2400 soc_LMEPm_field32_set(unit, &lmep_entry, PRIORITYf, 2401 endpoint_info->pkt_pri); 2402 2403 soc_LMEPm_field32_set(unit, &lmep_entry, VLAN_IDf, 2404 endpoint_info->vlan); 2405 2406 soc_LMEPm_field32_set(unit, &lmep_entry, CCMf, quantization_index); 2407 soc_LMEPm_field32_set(unit, &lmep_entry, DESTf, dst_glp); 2408 2409 soc_LMEPm_field32_set(unit, &lmep_entry, MH_OPCODEf, 2410 BCM_HG_OPCODE_UC); 2411 2412 soc_LMEPm_field32_set(unit, &lmep_entry, INT_PRIf, 2413 endpoint_info->int_pri); 2414 2415 /* Set Port status TLV in CCM Tx packets. */ 2416 if (endpoint_info->flags & BCM_OAM_ENDPOINT_PORT_STATE_UPDATE) { 2417 if ((endpoint_info->port_state != BCM_OAM_PORT_TLV_UP) 2418 && (endpoint_info->port_state != BCM_OAM_PORT_TLV_BLOCKED)) { 2419 return (BCM_E_PARAM); 2420 } 2421 soc_LMEPm_field32_set(unit, &lmep_entry, PORT_TLVf, 2422 (endpoint_info->port_state == BCM_OAM_PORT_TLV_UP) 2423 ? 1 : 0); 2424 } 2425 2426 /* Set Interface status TLV in CCM Tx packets - 1-bit wide. */ 2427 if (endpoint_info->flags 2428 & BCM_OAM_ENDPOINT_INTERFACE_STATE_UPDATE) { 2429 2430 if ((endpoint_info->interface_state 2431 != BCM_OAM_INTERFACE_TLV_UP) 2432 && (endpoint_info->interface_state 2433 != BCM_OAM_INTERFACE_TLV_DOWN)) { 2434 return (BCM_E_PARAM); 2435 } 2436 soc_LMEPm_field32_set(unit, &lmep_entry, INTERFACE_TLVf, 2437 (endpoint_info->interface_state 2438 == BCM_OAM_INTERFACE_TLV_UP) ? 1: 0); 2439 } 2440 2441 /* 2442 * When this bit is '1', both port and interface TLV values are set in 2443 * CCM Tx packets. 2444 */ 2445 if ((endpoint_info->flags 2446 & BCM_OAM_ENDPOINT_PORT_STATE_TX) 2447 || (endpoint_info->flags 2448 & BCM_OAM_ENDPOINT_INTERFACE_STATE_TX)) { 2449 soc_LMEPm_field32_set(unit, &lmep_entry, INSERT_TLVf, 1); 2450 } 2451 2452 /* Word-reverse the MAID bytes for the hardware */ 2453 2454 for (word_index = 0; 2455 word_index < (BCM_OAM_GROUP_NAME_LENGTH / 4); 2456 ++word_index) 2457 { 2458 reversed_maid[word_index] = 2459 ((uint32 *) group_p->name) 2460 [((BCM_OAM_GROUP_NAME_LENGTH / 4) - 1) - word_index]; 2461 } 2462 2463 soc_LMEPm_field_set(unit, &lmep_entry, MAIDf, reversed_maid); 2464 2465 SOC_IF_ERROR_RETURN(WRITE_LMEPm(unit, MEM_BLOCK_ALL, 2466 endpoint_p->local_tx_index, &lmep_entry)); 2467 2468 /* Local control block */ 2469 2470 SHR_BITSET(oam_info_p->local_tx_endpoints_in_use, 2471 endpoint_p->local_tx_index); 2472 } 2473 2474 if (local_rx_enabled) 2475 { 2476 rv = _bcm_tr2x_oam_find_free_local_endpoint_rx_index(unit, 2477 oam_info_p->local_rx_endpoints_in_use, 2478 oam_info_p->local_rx_endpoint_count, 2479 8, endpoint_info->level, endpoint_p); 2480 if (rv != BCM_E_NONE) 2481 { 2482 /* 2483 * Clean LMEP TX configuration. 2484 */ 2485 sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t)); 2486 SOC_IF_ERROR_RETURN(WRITE_LMEPm(unit, MEM_BLOCK_ALL, 2487 endpoint_p->local_tx_index, &lmep_entry)); 2488 /* 2489 * Local control block 2490 */ 2491 SHR_BITCLR(oam_info_p->local_tx_endpoints_in_use, 2492 endpoint_p->local_tx_index); 2493 return rv; 2494 } 2495 2496 /* MA_INDEX entry */ 2497 sal_memset(&ma_index_entry, 0, sizeof(ma_index_entry)); 2498 2499 soc_MA_INDEXm_field32_set(unit, &ma_index_entry, MA_PTRf, 2500 endpoint_info->group); 2501 2502 SOC_IF_ERROR_RETURN(WRITE_MA_INDEXm(unit, MEM_BLOCK_ALL, 2503 endpoint_p->local_rx_index, &ma_index_entry)); 2504 2505 /* L3 entry */ 2506 2507 L3_LOCK(unit); 2508 2509 if (BCM_SUCCESS(_bcm_tr2x_oam_find_lmep(unit, endpoint_info->vlan, 2510 src_glp, &l3_index, &l3_entry))) 2511 { 2512 /* There's already an entry for this vlan+glp */ 2513 2514 level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2515 LMEP__MDL_BITMAPf); 2516 2517 level_bitmap |= (1 << endpoint_info->level); 2518 2519 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm, 2520 l3_index, LMEP__MDL_BITMAPf, level_bitmap); 2521 2522 L3_UNLOCK(unit); 2523 2524 SHR_BITSET(oam_info_p->local_rx_endpoints_in_use, 2525 endpoint_p->local_rx_index); 2526 2527 SOC_IF_ERROR_RETURN(result); 2528 } 2529 else 2530 { 2531 /* This is the first entry at this vlan+glp */ 2532 2533 L3_UNLOCK(unit); 2534 2535 sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t)); 2536 2537 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2538 LMEP__MDL_BITMAPf, 1 << endpoint_info->level); 2539 2540 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2541 LMEP__MA_BASE_PTRf, 2542 endpoint_p->local_rx_index >> LEVEL_BIT_COUNT); 2543 2544 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2545 LMEP__DM_ENABLEf, (endpoint_info->flags & 2546 BCM_OAM_ENDPOINT_DELAY_MEASUREMENT) ? 1 : 0); 2547 2548 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2549 LMEP__CCM_ENABLEf, (endpoint_info->flags & 2550 BCM_OAM_ENDPOINT_CCM_RX) ? 1 : 0); 2551 2552 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2553 LMEP__LB_ENABLEf, (endpoint_info->flags & 2554 BCM_OAM_ENDPOINT_LOOPBACK) ? 1 : 0); 2555 2556 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, 2557 LMEP__LT_ENABLEf, (endpoint_info->flags & 2558 BCM_OAM_ENDPOINT_LINKTRACE) ? 1 : 0); 2559 2560 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, LMEP__VIDf, 2561 endpoint_info->vlan); 2562 2563 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, LMEP__SGLPf, 2564 src_glp); 2565 2566 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, KEY_TYPEf, 2567 TR_L3_HASH_KEY_TYPE_LMEP); 2568 2569 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, VALIDf, 1); 2570 2571 SOC_IF_ERROR_RETURN(soc_mem_insert(unit, L3_ENTRY_IPV4_UNICASTm, 2572 MEM_BLOCK_ALL, &l3_entry)); 2573 2574 /* Local control block */ 2575 2576 SHR_BITSET(oam_info_p->local_rx_endpoints_in_use, 2577 endpoint_p->local_rx_index); 2578 } 2579 } 2580 } 2581 2582 /* Local control block */ 2583 2584 endpoint_p->in_use = 1; 2585 2586 return BCM_E_NONE; 2587 } 2588 2589 static int _bcm_tr2x_oam_get_endpoint(int unit, int endpoint_index, 2590 _bcm_oam_endpoint_t *endpoint_p, bcm_oam_endpoint_info_t *endpoint_info) 2591 { 2592 rmep_entry_t rmep_entry; 2593 lmep_entry_t lmep_entry; 2594 l3_entry_ipv4_unicast_entry_t l3_key; 2595 l3_entry_ipv4_unicast_entry_t l3_entry; 2596 int l3_index; 2597 int quantization_index = 0; 2598 bcm_module_t mod_in, mod_out; 2599 bcm_port_t port_in, port_out; 2600 _bcm_gport_dest_t dest; 2601 2602 endpoint_info->id = endpoint_index; 2603 endpoint_info->group = endpoint_p->group_index; 2604 endpoint_info->name = endpoint_p->name; 2605 endpoint_info->level = endpoint_p->level; 2606 endpoint_info->vlan = endpoint_p->vlan; 2607 2608 if (endpoint_p->is_remote) 2609 { 2610 endpoint_info->flags |= BCM_OAM_ENDPOINT_REMOTE; 2611 2612 /* RMEP entry */ 2613 2614 SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY, 2615 endpoint_p->remote_index, 2616 &rmep_entry)); 2617 2618 /* Get endpoint faults and clear presistent faults if Clear is SET */ 2619 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_read_clear_faults(unit, 2620 endpoint_p->remote_index, 2621 endpoint_faults, 2622 RMEPm, 2623 (uint32 *) &rmep_entry, 2624 &endpoint_info->faults, 2625 &endpoint_info->persistent_faults, 2626 endpoint_info->clear_persistent_faults)); 2627 2628 2629 if (endpoint_info->flags2 & BCM_OAM_ENDPOINT_FLAGS2_GET_FAULTS_ONLY) { 2630 endpoint_info->flags2 &= ~BCM_OAM_ENDPOINT_FLAGS2_GET_FAULTS_ONLY; 2631 return BCM_E_NONE; 2632 } 2633 /* L3 entry */ 2634 _bcm_tr2x_oam_make_rmep_key(unit, &l3_key, endpoint_p->name, 2635 endpoint_p->level, endpoint_p->vlan, endpoint_p->glp); 2636 2637 if (BCM_FAILURE(soc_mem_search(unit, L3_ENTRY_IPV4_UNICASTm, MEM_BLOCK_ANY, 2638 &l3_index, &l3_key, &l3_entry, 0))) 2639 { 2640 return BCM_E_INTERNAL; 2641 } 2642 2643 quantization_index = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2644 RMEP__CCMf); 2645 } 2646 else 2647 { 2648 /* Endpoint is local */ 2649 2650 if (endpoint_p->local_tx_enabled) 2651 { 2652 /* LMEP entry */ 2653 2654 SOC_IF_ERROR_RETURN(READ_LMEPm(unit, MEM_BLOCK_ANY, 2655 endpoint_p->local_tx_index, &lmep_entry)); 2656 2657 soc_LMEPm_mac_addr_get(unit, &lmep_entry, SAf, 2658 endpoint_info->src_mac_address); 2659 2660 endpoint_info->pkt_pri = soc_LMEPm_field32_get(unit, &lmep_entry, 2661 PRIORITYf); 2662 2663 endpoint_info->int_pri = soc_LMEPm_field32_get(unit, &lmep_entry, 2664 INT_PRIf); 2665 2666 quantization_index = soc_LMEPm_field32_get(unit, &lmep_entry, 2667 CCMf); 2668 } 2669 2670 if (endpoint_p->local_rx_enabled) 2671 { 2672 /* L3 entry */ 2673 2674 if (BCM_FAILURE(_bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan, 2675 endpoint_p->glp, &l3_index, &l3_entry))) 2676 { 2677 return BCM_E_INTERNAL; 2678 } 2679 2680 if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2681 LMEP__DM_ENABLEf)) 2682 { 2683 endpoint_info->flags |= BCM_OAM_ENDPOINT_DELAY_MEASUREMENT; 2684 } 2685 2686 if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2687 LMEP__CCM_ENABLEf)) 2688 { 2689 endpoint_info->flags |= BCM_OAM_ENDPOINT_CCM_RX; 2690 } 2691 2692 if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2693 LMEP__LB_ENABLEf)) 2694 { 2695 endpoint_info->flags |= BCM_OAM_ENDPOINT_LOOPBACK; 2696 } 2697 2698 if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, 2699 LMEP__LT_ENABLEf)) 2700 { 2701 endpoint_info->flags |= BCM_OAM_ENDPOINT_LINKTRACE; 2702 } 2703 } 2704 } 2705 2706 if (endpoint_p->glp & (1 << 13)) 2707 { 2708 /* Trunk */ 2709 2710 BCM_GPORT_TRUNK_SET(endpoint_info->gport, endpoint_p->glp & 0x7F); 2711 } 2712 else 2713 { 2714 /* Modport */ 2715 2716 mod_in = (endpoint_p->glp & 0x0FC0) >> 6; 2717 port_in = (endpoint_p->glp & 0x3F); 2718 2719 BCM_IF_ERROR_RETURN 2720 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 2721 mod_in, port_in, &mod_out, &port_out)); 2722 2723 _bcm_gport_dest_t_init(&dest); 2724 dest.port = port_out; 2725 dest.modid = mod_out; 2726 dest.gport_type = BCM_GPORT_TYPE_MODPORT; 2727 BCM_IF_ERROR_RETURN( 2728 _bcm_esw_gport_construct(unit, &dest, &(endpoint_info->gport))); 2729 } 2730 2731 2732 endpoint_info->ccm_period = ccm_periods[quantization_index]; 2733 2734 return BCM_E_NONE; 2735 } 2736 2737 /* 2738 * Function: 2739 * bcm_tr2x_oam_endpoint_get 2740 * Purpose: 2741 * Get an OAM endpoint object 2742 * Parameters: 2743 * unit - (IN) Unit number. 2744 * endpoint - (IN) The ID of the endpoint object to get 2745 * endpoint_info - (OUT) Pointer to an OAM endpoint structure to receive the data 2746 * Returns: 2747 * BCM_E_XXX 2748 * Notes: 2749 */ 2750 int 2751 bcm_tr2x_oam_endpoint_get( 2752 int unit, 2753 bcm_oam_endpoint_t endpoint, 2754 bcm_oam_endpoint_info_t *endpoint_info) 2755 { 2756 _bcm_oam_info_t *oam_info_p; 2757 _bcm_oam_endpoint_t *endpoint_p; 2758 2759 SET_OAM_INFO; 2760 2761 CHECK_INIT; 2762 2763 VALIDATE_ENDPOINT_INDEX(endpoint); 2764 2765 SET_ENDPOINT(endpoint); 2766 2767 if (!endpoint_p->in_use) 2768 { 2769 return BCM_E_NOT_FOUND; 2770 } 2771 2772 return _bcm_tr2x_oam_get_endpoint(unit, endpoint, endpoint_p, 2773 endpoint_info); 2774 } 2775 2776 /* 2777 * Function: 2778 * bcm_tr2x_oam_endpoint_destroy 2779 * Purpose: 2780 * Destroy an OAM endpoint object 2781 * Parameters: 2782 * unit - (IN) Unit number. 2783 * endpoint - (IN) The ID of the OAM endpoint object to destroy 2784 * Returns: 2785 * BCM_E_XXX 2786 * Notes: 2787 */ 2788 int 2789 bcm_tr2x_oam_endpoint_destroy( 2790 int unit, 2791 bcm_oam_endpoint_t endpoint) 2792 { 2793 _bcm_oam_info_t *oam_info_p; 2794 _bcm_oam_endpoint_t *endpoint_p; 2795 2796 SET_OAM_INFO; 2797 2798 CHECK_INIT; 2799 2800 VALIDATE_ENDPOINT_INDEX(endpoint); 2801 2802 SET_ENDPOINT(endpoint); 2803 2804 if (!endpoint_p->in_use) 2805 { 2806 return BCM_E_NOT_FOUND; 2807 } 2808 2809 return _bcm_tr2x_oam_destroy_endpoint(unit, endpoint_p); 2810 } 2811 2812 /* 2813 * Function: 2814 * bcm_tr2x_oam_endpoint_destroy_all 2815 * Purpose: 2816 * Destroy all OAM endpoint objects associated with a given OAM 2817 * group 2818 * Parameters: 2819 * unit - (IN) Unit number. 2820 * group - (IN) The OAM group whose endpoints should be destroyed 2821 * Returns: 2822 * BCM_E_XXX 2823 * Notes: 2824 */ 2825 int 2826 bcm_tr2x_oam_endpoint_destroy_all( 2827 int unit, 2828 bcm_oam_group_t group) 2829 { 2830 _bcm_oam_info_t *oam_info_p; 2831 _bcm_oam_endpoint_t *endpoint_p; 2832 int endpoint_index; 2833 2834 SET_OAM_INFO; 2835 2836 CHECK_INIT; 2837 2838 VALIDATE_GROUP_INDEX(group); 2839 2840 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 2841 ++endpoint_index) 2842 { 2843 SET_ENDPOINT(endpoint_index); 2844 2845 if (endpoint_p->in_use && endpoint_p->group_index == group) 2846 { 2847 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_endpoint(unit, 2848 endpoint_p)); 2849 } 2850 } 2851 2852 return BCM_E_NONE; 2853 } 2854 2855 /* 2856 * Function: 2857 * bcm_tr2x_oam_endpoint_traverse 2858 * Purpose: 2859 * Traverse the set of OAM endpoints associated with the 2860 * specified group, calling a specified callback for each one 2861 * Parameters: 2862 * unit - (IN) Unit number. 2863 * group - (IN) The OAM group whose endpoints should be traversed 2864 * cb - (IN) A pointer to the callback function to call for each OAM endpoint in the specified group 2865 * user_data - (IN) Pointer to user data to supply in the callback 2866 * Returns: 2867 * BCM_E_XXX 2868 * Notes: 2869 */ 2870 int 2871 bcm_tr2x_oam_endpoint_traverse( 2872 int unit, 2873 bcm_oam_group_t group, 2874 bcm_oam_endpoint_traverse_cb cb, 2875 void *user_data) 2876 { 2877 _bcm_oam_info_t *oam_info_p; 2878 _bcm_oam_endpoint_t *endpoint_p; 2879 int endpoint_index; 2880 bcm_oam_endpoint_info_t endpoint_info; 2881 2882 SET_OAM_INFO; 2883 2884 CHECK_INIT; 2885 2886 VALIDATE_GROUP_INDEX(group); 2887 2888 if (cb == NULL) 2889 { 2890 return BCM_E_PARAM; 2891 } 2892 2893 for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count; 2894 ++endpoint_index) 2895 { 2896 SET_ENDPOINT(endpoint_index); 2897 2898 if (endpoint_p->in_use && endpoint_p->group_index == group) 2899 { 2900 bcm_oam_endpoint_info_t_init(&endpoint_info); 2901 2902 BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_get_endpoint(unit, 2903 endpoint_index, endpoint_p, &endpoint_info)); 2904 2905 BCM_IF_ERROR_RETURN(cb(unit, &endpoint_info, user_data)); 2906 } 2907 } 2908 2909 return BCM_E_NONE; 2910 } 2911 2912 /* 2913 * Function: 2914 * bcm_tr2x_oam_event_register 2915 * Purpose: 2916 * Register a callback for handling OAM events 2917 * Parameters: 2918 * unit - (IN) Unit number. 2919 * event_types - (IN) The set of OAM events for which the specified callback should be called 2920 * cb - (IN) A pointer to the callback function to call for the specified OAM events 2921 * user_data - (IN) Pointer to user data to supply in the callback 2922 * Returns: 2923 * BCM_E_XXX 2924 * Notes: 2925 */ 2926 int 2927 bcm_tr2x_oam_event_register( 2928 int unit, 2929 bcm_oam_event_types_t event_types, 2930 bcm_oam_event_cb cb, 2931 void *user_data) 2932 { 2933 _bcm_oam_info_t *oam_info_p; 2934 uint32 result; 2935 _bcm_oam_event_handler_t *event_handler_p; 2936 _bcm_oam_event_handler_t *previous_p = NULL; 2937 bcm_oam_event_type_t event_type; 2938 uint32 interrupt_control_register_value; 2939 int update_interrupt_control = 0; 2940 2941 SET_OAM_INFO; 2942 2943 CHECK_INIT; 2944 2945 if (cb == NULL) 2946 { 2947 return BCM_E_PARAM; 2948 } 2949 2950 /* Check and return error for unsupported events. */ 2951 SHR_BITTEST_RANGE(event_types.w, 2952 bcmOAMEventBHHLBTimeout, 2953 (bcmOAMEventCount - bcmOAMEventBHHLBTimeout), 2954 result); 2955 if (0 != result) { 2956 return (BCM_E_PARAM); 2957 } 2958 2959 SHR_BITTEST_RANGE(event_types.w, 0, bcmOAMEventCount, result); 2960 2961 if (result == 0) 2962 { 2963 return BCM_E_PARAM; 2964 } 2965 2966 for (event_handler_p = oam_info_p->event_handler_list_p; 2967 event_handler_p != NULL; 2968 event_handler_p = event_handler_p->next_p) 2969 { 2970 if (event_handler_p->cb == cb) 2971 { 2972 break; 2973 } 2974 2975 previous_p = event_handler_p; 2976 } 2977 2978 if (event_handler_p == NULL) 2979 { 2980 /* This handler hasn't been registered yet */ 2981 2982 event_handler_p = sal_alloc(sizeof(_bcm_oam_event_handler_t), 2983 "OAM event handler"); 2984 2985 if (event_handler_p == NULL) 2986 { 2987 return BCM_E_MEMORY; 2988 } 2989 2990 event_handler_p->next_p = NULL; 2991 event_handler_p->cb = cb; 2992 2993 SHR_BITCLR_RANGE(event_handler_p->event_types.w, 0, bcmOAMEventCount); 2994 2995 if (previous_p != NULL) 2996 { 2997 previous_p->next_p = event_handler_p; 2998 } 2999 else 3000 { 3001 oam_info_p->event_handler_list_p = event_handler_p; 3002 } 3003 } 3004 3005 SOC_IF_ERROR_RETURN(READ_CCM_INTERRUPT_CONTROLr(unit, 3006 &interrupt_control_register_value)); 3007 3008 for (event_type = 0; event_type < bcmOAMEventCount; ++event_type) 3009 { 3010 if (SHR_BITGET(event_types.w, event_type)) 3011 { 3012 if (interrupt_enable_fields[event_type] == INVALIDf) 3013 { 3014 return BCM_E_PARAM; 3015 } 3016 3017 if (!SHR_BITGET(event_handler_p->event_types.w, event_type)) 3018 { 3019 /* This handler isn't handling this event yet */ 3020 3021 SHR_BITSET(event_handler_p->event_types.w, event_type); 3022 3023 ++(oam_info_p->event_handler_count[event_type]); 3024 3025 if (oam_info_p->event_handler_count[event_type] == 1) 3026 { 3027 /* This is the first handler for this event */ 3028 3029 update_interrupt_control = 1; 3030 3031 soc_reg_field_set(unit, CCM_INTERRUPT_CONTROLr, 3032 &interrupt_control_register_value, 3033 interrupt_enable_fields[event_type], 1); 3034 } 3035 } 3036 } 3037 } 3038 3039 event_handler_p->user_data = user_data; 3040 3041 /* Enable any needed interrupts not yet enabled */ 3042 3043 if (update_interrupt_control) 3044 { 3045 SOC_IF_ERROR_RETURN(WRITE_CCM_INTERRUPT_CONTROLr(unit, 3046 interrupt_control_register_value)); 3047 } 3048 3049 return BCM_E_NONE; 3050 } 3051 3052 /* 3053 * Function: 3054 * bcm_tr2x_oam_event_unregister 3055 * Purpose: 3056 * Unregister a callback for handling OAM events 3057 * Parameters: 3058 * unit - (IN) Unit number. 3059 * event_types - (IN) The set of OAM events for which the specified callback should not be called 3060 * cb - (IN) A pointer to the callback function to unregister from the specified OAM events 3061 * Returns: 3062 * BCM_E_XXX 3063 * Notes: 3064 */ 3065 int 3066 bcm_tr2x_oam_event_unregister( 3067 int unit, 3068 bcm_oam_event_types_t event_types, 3069 bcm_oam_event_cb cb) 3070 { 3071 _bcm_oam_info_t *oam_info_p; 3072 uint32 result; 3073 _bcm_oam_event_handler_t *event_handler_p; 3074 _bcm_oam_event_handler_t *previous_p = NULL; 3075 bcm_oam_event_type_t event_type; 3076 uint32 interrupt_control_register_value; 3077 int update_interrupt_control = 0; 3078 3079 SET_OAM_INFO; 3080 3081 CHECK_INIT; 3082 3083 if (cb == NULL) 3084 { 3085 return BCM_E_PARAM; 3086 } 3087 3088 SHR_BITTEST_RANGE(event_types.w, 0, bcmOAMEventCount, result); 3089 3090 if (result == 0) 3091 { 3092 return BCM_E_PARAM; 3093 } 3094 3095 for (event_handler_p = oam_info_p->event_handler_list_p; 3096 event_handler_p != NULL; 3097 event_handler_p = event_handler_p->next_p) 3098 { 3099 if (event_handler_p->cb == cb) 3100 { 3101 break; 3102 } 3103 3104 previous_p = event_handler_p; 3105 } 3106 3107 if (event_handler_p == NULL) 3108 { 3109 return BCM_E_NOT_FOUND; 3110 } 3111 3112 SOC_IF_ERROR_RETURN(READ_CCM_INTERRUPT_CONTROLr(unit, 3113 &interrupt_control_register_value)); 3114 3115 for (event_type = 0; event_type < bcmOAMEventCount; ++event_type) 3116 { 3117 if (SHR_BITGET(event_types.w, event_type)) 3118 { 3119 if (interrupt_enable_fields[event_type] == INVALIDf) 3120 { 3121 return BCM_E_UNAVAIL; 3122 } 3123 if (oam_info_p->event_handler_count[event_type] > 0 && 3124 SHR_BITGET(event_handler_p->event_types.w, event_type)) 3125 { 3126 /* This handler has been handling this event */ 3127 3128 SHR_BITCLR(event_handler_p->event_types.w, event_type); 3129 3130 --(oam_info_p->event_handler_count[event_type]); 3131 3132 if (oam_info_p->event_handler_count[event_type] == 0) 3133 { 3134 /* No more handlers for this event */ 3135 3136 update_interrupt_control = 1; 3137 3138 soc_reg_field_set(unit, CCM_INTERRUPT_CONTROLr, 3139 &interrupt_control_register_value, 3140 interrupt_enable_fields[event_type], 0); 3141 } 3142 } 3143 } 3144 } 3145 3146 /* Disable any interrupts that lost their last handler */ 3147 3148 if (update_interrupt_control) 3149 { 3150 SOC_IF_ERROR_RETURN(WRITE_CCM_INTERRUPT_CONTROLr(unit, 3151 interrupt_control_register_value)); 3152 } 3153 3154 SHR_BITTEST_RANGE(event_handler_p->event_types.w, 0, bcmOAMEventCount, 3155 result); 3156 3157 if (result == 0) 3158 { 3159 /* No more events for this handler to handle */ 3160 3161 if (previous_p != NULL) 3162 { 3163 previous_p->next_p = event_handler_p->next_p; 3164 } 3165 else 3166 { 3167 oam_info_p->event_handler_list_p = event_handler_p->next_p; 3168 } 3169 3170 sal_free(event_handler_p); 3171 } 3172 3173 return BCM_E_NONE; 3174 } 3175 3176 #if defined(BCM_WARM_BOOT_SUPPORT) 3177 int _bcm_tr2x_oam_sync(int unit) 3178 { 3179 _bcm_oam_info_t *oam_info_p; 3180 _bcm_oam_group_t *group_p; 3181 int allocation_size = 0; 3182 int group_index; 3183 int stable_size; 3184 soc_scache_handle_t scache_handle; 3185 uint8 *group_names_p; 3186 int rv = BCM_E_INTERNAL; 3187 3188 SET_OAM_INFO; 3189 3190 CHECK_INIT; 3191 3192 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 3193 if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) || (stable_size == 0)) { 3194 return BCM_E_NONE; 3195 } 3196 3197 /* Calculate memory size required to store group names on this device */ 3198 allocation_size = (oam_info_p->group_count 3199 * (BCM_OAM_GROUP_NAME_LENGTH)); 3200 3201 /* Set OAM module scache handle */ 3202 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0); 3203 3204 /* Check if memory has already been allocated */ 3205 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 0, allocation_size, 3206 &group_names_p, BCM_WB_DEFAULT_VERSION, 3207 NULL); 3208 if (!SOC_WARM_BOOT(unit) && (BCM_E_NOT_FOUND == rv)) { 3209 /* Allocate scache memory as it has not been allocated */ 3210 BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 1, 3211 allocation_size, 3212 &group_names_p, 3213 BCM_WB_DEFAULT_VERSION, 3214 NULL)); 3215 if (group_names_p == NULL) { 3216 return BCM_E_MEMORY; 3217 } 3218 } 3219 3220 /* Save group names in the scache memory */ 3221 for (group_index = 0; group_index < oam_info_p->group_count; 3222 ++group_index) 3223 { 3224 SET_GROUP(group_index); 3225 3226 if (group_p->in_use) 3227 { 3228 sal_memcpy(group_names_p, group_p->name, BCM_OAM_GROUP_NAME_LENGTH); 3229 3230 group_names_p += BCM_OAM_GROUP_NAME_LENGTH; 3231 } 3232 } 3233 3234 return BCM_E_NONE; 3235 } 3236 #endif /* BCM_WARM_BOOT_SUPPORT */ 3237 3238 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 3239 /* 3240 * Function: 3241 * _bcm_oam_sw_dump 3242 * Purpose: 3243 * Displays oam information maintained by software. 3244 * Parameters: 3245 * unit - Device unit number 3246 * Returns: 3247 * None 3248 */ 3249 void 3250 _bcm_tr2x_oam_sw_dump(int unit) 3251 { 3252 _bcm_oam_info_t *oam_info_p; 3253 _bcm_oam_endpoint_t *endpoint_p; 3254 int group_idx, endpoint_idx; 3255 SHR_BITDCL word; 3256 3257 SET_OAM_INFO; 3258 3259 LOG_CLI((BSL_META_U(unit, 3260 "\nSW Information OAM - Unit %d\n"), unit)); 3261 LOG_CLI((BSL_META_U(unit, 3262 " Group Info : \n"))); 3263 3264 for (group_idx = 0; group_idx < oam_info_p->group_count; group_idx++) { 3265 if (oam_info_p->groups[group_idx].in_use) { 3266 LOG_CLI((BSL_META_U(unit, 3267 "Group %d is in use\n"), group_idx)); 3268 } 3269 } 3270 3271 LOG_CLI((BSL_META_U(unit, 3272 "\n local_tx_endpoints_in_use \n"))); 3273 for (word = 0; word < _SHR_BITDCLSIZE 3274 (oam_info_p->local_tx_endpoint_count); word++) { 3275 LOG_CLI((BSL_META_U(unit, 3276 " word %d value %x "), word, 3277 oam_info_p->local_tx_endpoints_in_use[word])); 3278 } 3279 3280 LOG_CLI((BSL_META_U(unit, 3281 "\n local_rx_endpoints_in_use \n"))); 3282 for (word = 0; word < _SHR_BITDCLSIZE 3283 (oam_info_p->local_rx_endpoint_count); word++) { 3284 LOG_CLI((BSL_META_U(unit, 3285 " word %d value %x "), word, 3286 oam_info_p->local_rx_endpoints_in_use[word])); 3287 } 3288 3289 LOG_CLI((BSL_META_U(unit, 3290 "\n remote_endpoints_in_use \n"))); 3291 for (word = 0; word < _SHR_BITDCLSIZE 3292 (oam_info_p->remote_endpoint_count); word++) { 3293 LOG_CLI((BSL_META_U(unit, 3294 " word %d value %x "), word, 3295 oam_info_p->remote_endpoints_in_use[word])); 3296 } 3297 3298 LOG_CLI((BSL_META_U(unit, 3299 "\n Reverse RMEP lookup \n"))); 3300 for (endpoint_idx = 0; endpoint_idx < oam_info_p->remote_endpoint_count; 3301 endpoint_idx++) { 3302 if (oam_info_p->endpoints 3303 [oam_info_p->remote_endpoints[endpoint_idx]].in_use) { 3304 LOG_CLI((BSL_META_U(unit, 3305 "RMEP %x \n"), 3306 oam_info_p->remote_endpoints[endpoint_idx])); 3307 } 3308 } 3309 3310 LOG_CLI((BSL_META_U(unit, 3311 "\n Endpoint Information \n"))); 3312 for (endpoint_idx = 0; endpoint_idx < oam_info_p->endpoint_count; 3313 endpoint_idx++) { 3314 SET_ENDPOINT(endpoint_idx); 3315 if (!endpoint_p->in_use) { 3316 continue; 3317 } 3318 LOG_CLI((BSL_META_U(unit, 3319 "\n Endpoint index %d\n"), endpoint_idx)); 3320 LOG_CLI((BSL_META_U(unit, 3321 "\t Group index %d\n"), endpoint_p->group_index)); 3322 LOG_CLI((BSL_META_U(unit, 3323 "\t Name %x\n"), endpoint_p->name)); 3324 LOG_CLI((BSL_META_U(unit, 3325 "\t Level %d\n"), endpoint_p->level)); 3326 LOG_CLI((BSL_META_U(unit, 3327 "\t VLAN %d\n"), endpoint_p->vlan)); 3328 LOG_CLI((BSL_META_U(unit, 3329 "\t GLP %x\n"), endpoint_p->glp)); 3330 LOG_CLI((BSL_META_U(unit, 3331 "\t local_tx_enabled %d\n"), endpoint_p->local_tx_enabled)); 3332 LOG_CLI((BSL_META_U(unit, 3333 "\t local_rx_enabled %d\n"), endpoint_p->local_rx_enabled)); 3334 LOG_CLI((BSL_META_U(unit, 3335 "\t remote_index %d\n"), endpoint_p->remote_index)); 3336 LOG_CLI((BSL_META_U(unit, 3337 "\t local_tx_index %d\n"), endpoint_p->local_tx_index)); 3338 LOG_CLI((BSL_META_U(unit, 3339 "\t local_rx_index %d\n"), endpoint_p->local_rx_index)); 3340 } 3341 return; 3342 } 3343 #endif 3344 #endif /* defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_APOLLO_SUPPORT) || \ 3345 defined(BCM_VALKYRIE2_SUPPORT)*/