port.c (18910B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 */ 7 8 #include <soc/defs.h> 9 #include <sal/core/libc.h> 10 11 #if defined(BCM_TRIUMPH3_SUPPORT) 12 13 #include <soc/drv.h> 14 #include <soc/macutil.h> 15 #include <bcm/error.h> 16 #include <bcm_int/esw/port.h> 17 #include <bcm_int/esw/stack.h> 18 #include <bcm_int/esw/trident.h> 19 #include <bcm_int/esw_dispatch.h> 20 #include <bcm_int/common/lock.h> 21 22 /* 23 * Function: 24 * bcm_tr3_port_esm_eligible_set 25 * Description: 26 * Set a port's ESM lookup eligibility. The port may be a remote port. 27 * Parameters: 28 * unit - (IN) Device number 29 * port - (IN) Port number 30 * value - (IN) TRUE = eligible, FALSE = not eligible. 31 * Return Value: 32 * BCM_E_XXX 33 */ 34 int 35 bcm_tr3_port_esm_eligible_set(int unit, bcm_port_t port, int value) 36 { 37 bcm_module_t mod_out; 38 bcm_port_t port_out; 39 bcm_trunk_t tid_out; 40 int id_out; 41 int stm_index; 42 bcm_module_t my_modid; 43 int rv = BCM_E_NONE; 44 source_trunk_map_table_entry_t stm_entry; 45 46 if (!soc_feature(unit, soc_feature_etu_support)) { 47 return BCM_E_UNAVAIL; 48 } 49 50 /* Derive index to SOURCE_TRUNK_MAP table based on module ID and port */ 51 if (BCM_GPORT_IS_SET(port)) { 52 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, 53 &mod_out, &port_out, &tid_out, &id_out)); 54 if (-1 != tid_out || -1 != id_out) { 55 return BCM_E_PORT; 56 } 57 BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 58 mod_out, port_out, &stm_index)); 59 } else { 60 if (!SOC_PORT_VALID(unit, port)) { 61 return BCM_E_PORT; 62 } 63 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 64 BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 65 my_modid, port, &stm_index)); 66 } 67 68 /* Update ESM fields */ 69 soc_mem_lock(unit, SOURCE_TRUNK_MAP_TABLEm); 70 rv = READ_SOURCE_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ANY, stm_index, 71 &stm_entry); 72 if (BCM_FAILURE(rv)) { 73 soc_mem_unlock(unit, SOURCE_TRUNK_MAP_TABLEm); 74 return rv; 75 } 76 77 if (value) { 78 soc_SOURCE_TRUNK_MAP_TABLEm_field32_set(unit, &stm_entry, 79 ESM_SEARCH_OFFSETf, 1); 80 soc_SOURCE_TRUNK_MAP_TABLEm_field32_set(unit, &stm_entry, 81 ESM_SEARCH_PRIORITYf, 7); 82 } else { 83 soc_SOURCE_TRUNK_MAP_TABLEm_field32_set(unit, &stm_entry, 84 ESM_SEARCH_OFFSETf, 0); 85 soc_SOURCE_TRUNK_MAP_TABLEm_field32_set(unit, &stm_entry, 86 ESM_SEARCH_PRIORITYf, 0); 87 } 88 89 rv = WRITE_SOURCE_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ALL, stm_index, 90 &stm_entry); 91 if (BCM_FAILURE(rv)) { 92 soc_mem_unlock(unit, SOURCE_TRUNK_MAP_TABLEm); 93 return rv; 94 } 95 96 soc_mem_unlock(unit, SOURCE_TRUNK_MAP_TABLEm); 97 return BCM_E_NONE; 98 } 99 100 /* 101 * Function: 102 * bcm_tr3_port_esm_eligible_get 103 * Description: 104 * Get a port's ESM lookup eligibility. The port may be a remote port. 105 * Parameters: 106 * unit - (IN) Device number 107 * port - (IN) Port number 108 * value - (OUT) TRUE = eligible, FALSE = not eligible. 109 * Return Value: 110 * BCM_E_XXX 111 */ 112 int 113 bcm_tr3_port_esm_eligible_get(int unit, bcm_port_t port, int *value) 114 { 115 bcm_module_t mod_out; 116 bcm_port_t port_out; 117 bcm_trunk_t tid_out; 118 int id_out; 119 int stm_index; 120 bcm_module_t my_modid; 121 source_trunk_map_table_entry_t stm_entry; 122 123 if (!soc_feature(unit, soc_feature_etu_support)) { 124 return BCM_E_UNAVAIL; 125 } 126 127 /* Derive index to SOURCE_TRUNK_MAP table based on module ID and port */ 128 if (BCM_GPORT_IS_SET(port)) { 129 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, 130 &mod_out, &port_out, &tid_out, &id_out)); 131 if (-1 != tid_out || -1 != id_out) { 132 return BCM_E_PORT; 133 } 134 BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 135 mod_out, port_out, &stm_index)); 136 } else { 137 if (!SOC_PORT_VALID(unit, port)) { 138 return BCM_E_PORT; 139 } 140 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 141 BCM_IF_ERROR_RETURN(_bcm_esw_src_mod_port_table_index_get(unit, 142 my_modid, port, &stm_index)); 143 } 144 145 /* Get ESM fields */ 146 SOC_IF_ERROR_RETURN(READ_SOURCE_TRUNK_MAP_TABLEm(unit, MEM_BLOCK_ANY, 147 stm_index, &stm_entry)); 148 if (soc_SOURCE_TRUNK_MAP_TABLEm_field32_get(unit, &stm_entry, 149 ESM_SEARCH_OFFSETf) && 150 soc_SOURCE_TRUNK_MAP_TABLEm_field32_get(unit, &stm_entry, 151 ESM_SEARCH_PRIORITYf)) { 152 *value = TRUE; 153 } else { 154 *value = FALSE; 155 } 156 157 return BCM_E_NONE; 158 } 159 160 /* 161 * Function: 162 * bcm_tr3_port_extender_type_set 163 * Description: 164 * Set Port Extender port type. 165 * Parameters: 166 * unit - (IN) Device number 167 * port - (IN) Port number 168 * value - (IN) Port type 169 * Return Value: 170 * BCM_E_XXX 171 */ 172 int 173 bcm_tr3_port_extender_type_set(int unit, bcm_port_t port, int value) 174 { 175 switch (value) { 176 case BCM_PORT_EXTENDER_TYPE_SWITCH: 177 BCM_IF_ERROR_RETURN(bcm_td_port_niv_type_set(unit, port, 178 BCM_PORT_NIV_TYPE_SWITCH)); 179 break; 180 case BCM_PORT_EXTENDER_TYPE_UPLINK: 181 BCM_IF_ERROR_RETURN(bcm_td_port_niv_type_set(unit, port, 182 BCM_PORT_NIV_TYPE_UPLINK)); 183 break; 184 case BCM_PORT_EXTENDER_TYPE_DOWNLINK_ACCESS: 185 BCM_IF_ERROR_RETURN(bcm_td_port_niv_type_set(unit, port, 186 BCM_PORT_NIV_TYPE_DOWNLINK_ACCESS)); 187 BCM_IF_ERROR_RETURN(_bcm_esw_port_tab_set(unit, port, 188 _BCM_CPU_TABS_ETHER, VNTAG_ACTIONS_IF_NOT_PRESENTf, 189 2)); 190 break; 191 case BCM_PORT_EXTENDER_TYPE_DOWNLINK_TRANSIT: 192 BCM_IF_ERROR_RETURN(bcm_td_port_niv_type_set(unit, port, 193 BCM_PORT_NIV_TYPE_DOWNLINK_TRANSIT)); 194 break; 195 case BCM_PORT_EXTENDER_TYPE_NONE: 196 BCM_IF_ERROR_RETURN( 197 bcm_td_port_niv_type_set(unit, port, BCM_PORT_NIV_TYPE_NONE)); 198 break; 199 default: 200 return BCM_E_PARAM; 201 } 202 203 return BCM_E_NONE; 204 } 205 206 /* 207 * Function: 208 * bcm_tr3_port_extender_type_get 209 * Description: 210 * Get Port Extender port type. 211 * Parameters: 212 * unit - (IN) Device number 213 * port - (IN) Port number 214 * value - (IN) Port type 215 * Return Value: 216 * BCM_E_XXX 217 */ 218 int 219 bcm_tr3_port_extender_type_get(int unit, bcm_port_t port, int *value) 220 { 221 int type; 222 223 BCM_IF_ERROR_RETURN(bcm_td_port_niv_type_get(unit, port, &type)); 224 switch (type) { 225 case BCM_PORT_NIV_TYPE_SWITCH: 226 *value = BCM_PORT_EXTENDER_TYPE_SWITCH; 227 break; 228 case BCM_PORT_NIV_TYPE_UPLINK: 229 *value = BCM_PORT_EXTENDER_TYPE_UPLINK; 230 break; 231 case BCM_PORT_NIV_TYPE_DOWNLINK_ACCESS: 232 *value = BCM_PORT_EXTENDER_TYPE_DOWNLINK_ACCESS; 233 break; 234 case BCM_PORT_NIV_TYPE_DOWNLINK_TRANSIT: 235 *value = BCM_PORT_EXTENDER_TYPE_DOWNLINK_TRANSIT; 236 break; 237 case BCM_PORT_NIV_TYPE_NONE: 238 *value = BCM_PORT_EXTENDER_TYPE_NONE; 239 break; 240 default: 241 return BCM_E_INTERNAL; 242 } 243 244 return BCM_E_NONE; 245 } 246 247 #if defined(INCLUDE_L3) 248 /* 249 * Function: 250 * bcm_tr3_port_etag_pcp_de_source_set 251 * Description: 252 * Set source of ETAG's PCP and DE fields. 253 * Parameters: 254 * unit - (IN) Device number 255 * port - (IN) Port number 256 * value - (IN) PCP and DE source 257 * Return Value: 258 * BCM_E_XXX 259 */ 260 int 261 bcm_tr3_port_etag_pcp_de_source_set(int unit, bcm_port_t port, int value) 262 { 263 int source; 264 265 switch (value) { 266 case BCM_EXTENDER_PCP_DE_SELECT_OUTER_TAG: 267 source = 0; 268 break; 269 case BCM_EXTENDER_PCP_DE_SELECT_INNER_TAG: 270 source = 1; 271 break; 272 case BCM_EXTENDER_PCP_DE_SELECT_DEFAULT: 273 source = 2; 274 break; 275 case BCM_EXTENDER_PCP_DE_SELECT_PHB: 276 source = 3; 277 break; 278 default: 279 return BCM_E_PARAM; 280 } 281 282 BCM_IF_ERROR_RETURN(_bcm_esw_port_tab_set(unit, port, _BCM_CPU_TABS_ETHER, 283 ETAG_PCP_DE_SOURCEf, source)); 284 if (SOC_MEM_IS_VALID(unit, EGR_ING_PORTm)) { 285 BCM_IF_ERROR_RETURN(soc_mem_field32_modify(unit, EGR_ING_PORTm, port, 286 ETAG_PCP_DE_SOURCEf, source)); 287 } 288 289 return BCM_E_NONE; 290 } 291 292 /* 293 * Function: 294 * bcm_tr3_port_etag_pcp_de_source_get 295 * Description: 296 * Get source of ETAG's PCP and DE fields. 297 * Parameters: 298 * unit - (IN) Device number 299 * port - (IN) Port number 300 * value - (IN) PCP and DE source 301 * Return Value: 302 * BCM_E_XXX 303 */ 304 int 305 bcm_tr3_port_etag_pcp_de_source_get(int unit, bcm_port_t port, int *value) 306 { 307 int source; 308 309 BCM_IF_ERROR_RETURN(_bcm_esw_port_tab_get(unit, port, ETAG_PCP_DE_SOURCEf, 310 &source)); 311 312 switch (source) { 313 case 0: 314 *value = BCM_EXTENDER_PCP_DE_SELECT_OUTER_TAG; 315 break; 316 case 1: 317 *value = BCM_EXTENDER_PCP_DE_SELECT_INNER_TAG; 318 break; 319 case 2: 320 *value = BCM_EXTENDER_PCP_DE_SELECT_DEFAULT; 321 break; 322 case 3: 323 *value = BCM_EXTENDER_PCP_DE_SELECT_PHB; 324 break; 325 default: 326 return BCM_E_INTERNAL; 327 } 328 329 return BCM_E_NONE; 330 } 331 #endif /* INCLUDE_L3 */ 332 333 int 334 bcm_tr3_port_pps_rate_egress_set(int unit, bcm_port_t port, 335 uint32 pps, uint32 burst) 336 { 337 uint32 miscval; 338 uint64 regval; 339 uint32 refresh_rate, bucketsize, granularity = 3, flags = 0; 340 int refresh_bitsize, bucket_bitsize; 341 342 /* 343 * The procedure followed is first disable the egress metering i.e. 344 * reset EGRMETERINGCONFIG, then clear the buckets and re-enable the 345 * egress metering. Finally enable the MISCCONFING,Metering clocking 346 * 347 * NOTE: During the period of disabling and re-enabling the Egress metering 348 * may be in-effective for couple of cycles 349 */ 350 351 /* Disable egress metering for this port */ 352 BCM_IF_ERROR_RETURN(READ_EGRMETERINGCONFIG_64r(unit, port, ®val)); 353 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, REFRESHf, 0); 354 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, THD_SELf, 0); 355 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGCONFIG_64r(unit, port, regval)); 356 357 /* Reset metering bucket. */ 358 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGBUCKETr(unit, port, 0)); 359 360 /* If pps=0, metering is disabled on this egress port*/ 361 if (pps) { 362 /* Enable metering for this port */ 363 364 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &miscval)); 365 if (soc_reg_field_get(unit, MISCCONFIGr, miscval, ITU_MODE_SELf)) { 366 flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 367 } 368 flags |= _BCM_TD_METER_FLAG_PACKET_MODE; 369 refresh_bitsize = soc_reg_field_length(unit, EGRMETERINGCONFIG_64r, REFRESHf); 370 bucket_bitsize = soc_reg_field_length(unit, EGRMETERINGCONFIG_64r, THD_SELf); 371 BCM_IF_ERROR_RETURN 372 (_bcm_td_rate_to_bucket_encoding(unit, pps, burst, flags, 373 refresh_bitsize, bucket_bitsize, 374 &refresh_rate, &bucketsize, &granularity)); 375 376 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, MODEf, 1); 377 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 378 METER_GRANf, granularity); 379 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 380 REFRESHf, refresh_rate); 381 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 382 THD_SELf, bucketsize); 383 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGCONFIG_64r(unit, port, regval)); 384 } 385 386 return BCM_E_NONE; 387 } 388 389 int 390 bcm_tr3_port_pps_rate_egress_get(int unit, bcm_port_t port, 391 uint32 *pps, uint32 *burst) 392 { 393 uint64 regval; 394 uint32 miscval; 395 uint32 refresh_rate = 0, bucketsize = 0, granularity = 3, flags = 0; 396 397 COMPILER_64_ZERO(regval); 398 399 /* Input parameters check. */ 400 if (!pps || !burst) { 401 return (BCM_E_PARAM); 402 } 403 404 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &miscval)); 405 if (soc_reg_field_get(unit, MISCCONFIGr, miscval, ITU_MODE_SELf)) { 406 flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 407 } 408 409 BCM_IF_ERROR_RETURN(READ_EGRMETERINGCONFIG_64r(unit, port, ®val)); 410 411 bucketsize = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 412 regval, THD_SELf); 413 refresh_rate = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 414 regval, REFRESHf); 415 flags |= _BCM_TD_METER_FLAG_PACKET_MODE; 416 417 granularity = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 418 regval, METER_GRANf); 419 BCM_IF_ERROR_RETURN 420 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 421 granularity, flags, pps, burst)); 422 423 return (BCM_E_NONE); 424 } 425 426 int 427 bcm_tr3_port_rate_egress_set(int unit, bcm_port_t port, 428 uint32 kbits_sec, uint32 kbits_burst, uint32 mode) 429 { 430 uint32 miscval; 431 uint64 regval; 432 uint32 refresh_rate, bucketsize, granularity = 3, flags = 0; 433 int refresh_bitsize, bucket_bitsize; 434 435 if (mode == _BCM_PORT_RATE_PPS_MODE) { 436 return bcm_tr3_port_pps_rate_egress_set( 437 unit, port, kbits_sec, kbits_burst); 438 } 439 440 /* 441 * The procedure followed is first disable the egress metering i.e. 442 * reset EGRMETERINGCONFIG, then clear the buckets and re-enable the 443 * egress metering. Finally enable the MISCCONFING,Metering clocking 444 * 445 * NOTE: During the period of disabling and re-enabling the Egress metering 446 * may be in-effective for couple of cycles 447 */ 448 449 /* Disable egress metering for this port */ 450 BCM_IF_ERROR_RETURN(READ_EGRMETERINGCONFIG_64r(unit, port, ®val)); 451 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, REFRESHf, 0); 452 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, THD_SELf, 0); 453 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGCONFIG_64r(unit, port, regval)); 454 455 /* Reset metering bucket. */ 456 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGBUCKETr(unit, port, 0)); 457 458 /* If kbits_sec=0, metering is disabled on this egress port*/ 459 if (kbits_sec) { 460 /* Enable metering for this port */ 461 462 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &miscval)); 463 if (soc_reg_field_get(unit, MISCCONFIGr, miscval, ITU_MODE_SELf)) { 464 flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 465 } 466 refresh_bitsize = soc_reg_field_length(unit, EGRMETERINGCONFIG_64r, 467 REFRESHf); 468 bucket_bitsize = soc_reg_field_length(unit, EGRMETERINGCONFIG_64r, 469 THD_SELf); 470 BCM_IF_ERROR_RETURN 471 (_bcm_td_rate_to_bucket_encoding(unit, kbits_sec, kbits_burst, flags, 472 refresh_bitsize, bucket_bitsize, 473 &refresh_rate, &bucketsize, &granularity)); 474 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, MODEf, 0); 475 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 476 METER_GRANf, granularity); 477 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 478 REFRESHf, refresh_rate); 479 soc_reg64_field32_set(unit, EGRMETERINGCONFIG_64r, ®val, 480 THD_SELf, bucketsize); 481 BCM_IF_ERROR_RETURN(WRITE_EGRMETERINGCONFIG_64r(unit, port, regval)); 482 } 483 484 return BCM_E_NONE; 485 } 486 487 int 488 bcm_tr3_port_rate_egress_get(int unit, bcm_port_t port, 489 uint32 *kbits_sec, uint32 *kbits_burst, uint32 *mode) 490 { 491 uint64 regval; /* EGRMETERINGCONFIGr register value. */ 492 uint32 miscval; 493 uint32 refresh_rate = 0, bucketsize = 0, granularity = 3, flags = 0; 494 495 COMPILER_64_ZERO(regval); 496 497 /* Input parameters check. */ 498 if (!kbits_sec || !kbits_burst) { 499 return (BCM_E_PARAM); 500 } 501 502 BCM_IF_ERROR_RETURN(READ_MISCCONFIGr(unit, &miscval)); 503 if (soc_reg_field_get(unit, MISCCONFIGr, miscval, ITU_MODE_SELf)) { 504 flags |= _BCM_TD_METER_FLAG_NON_LINEAR; 505 } 506 507 BCM_IF_ERROR_RETURN(READ_EGRMETERINGCONFIG_64r(unit, port, ®val)); 508 509 if (1 == soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 510 regval, MODEf)) { 511 *mode = _BCM_PORT_RATE_PPS_MODE; 512 return bcm_tr3_port_pps_rate_egress_get(unit, port, 513 kbits_sec, kbits_burst); 514 } 515 516 bucketsize = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 517 regval, THD_SELf); 518 refresh_rate = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 519 regval, REFRESHf); 520 granularity = soc_reg64_field32_get(unit, EGRMETERINGCONFIG_64r, 521 regval, METER_GRANf); 522 BCM_IF_ERROR_RETURN 523 (_bcm_td_bucket_encoding_to_rate(unit, refresh_rate, bucketsize, 524 granularity, flags, 525 kbits_sec, kbits_burst)); 526 527 return (BCM_E_NONE); 528 } 529 /* 530 * Function: 531 * bcm_tr3_cpu_port_drain_cells 532 * Purpose: 533 * To drain cells on CPU port (no MAC Control Needed) 534 * Parameters: 535 * unit - (IN) unit number 536 * port - (IN) Port 537 * Returns: 538 * BCM_E_XXX 539 */ 540 int bcm_tr3_cpu_port_drain_cells(int unit, int port) 541 { 542 return soc_egress_drain_cells(unit, port, 250000); 543 } 544 545 /* 546 * Function: 547 * _bcm_tr3_port_drain_cells 548 * Purpose: 549 * To drain cells associated to the port. 550 * Parameters: 551 * unit - (IN) unit number 552 * port - (IN) Port 553 * Returns: 554 * BCM_E_XXX 555 */ 556 int bcm_tr3_port_drain_cells(int unit, int port) 557 { 558 mac_driver_t *macd; 559 int rv = BCM_E_NONE; 560 561 PORT_LOCK(unit); 562 if (IS_CPU_PORT(unit, port)) 563 { 564 rv = bcm_tr3_cpu_port_drain_cells(unit, port); 565 PORT_UNLOCK(unit); 566 return rv; 567 } 568 rv = soc_mac_probe(unit, port, &macd); 569 570 if (!BCM_SUCCESS(rv)) { 571 PORT_UNLOCK(unit); 572 return rv; 573 } 574 /* Drain cells from queue */ 575 rv = MAC_CONTROL_SET(macd, unit, port, SOC_MAC_CONTROL_EGRESS_DRAIN, 1); 576 PORT_UNLOCK(unit); 577 return rv; 578 } 579 580 581 #endif /* BCM_TRIUMPH3_SUPPORT */