l2station.c (64735B)
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 * File: l2.c 8 * Purpose: Tomahawk3 L2 Station API internal functions 9 */ 10 11 #include <shared/bsl.h> 12 #include <soc/defs.h> 13 #include <assert.h> 14 #include <sal/core/libc.h> 15 #include <soc/mem.h> 16 #include <soc/cm.h> 17 #include <soc/drv.h> 18 #include <soc/register.h> 19 #include <soc/memory.h> 20 #include <soc/hash.h> 21 #include <soc/l2x.h> 22 #include <soc/triumph.h> 23 #include <bcm/l2.h> 24 #include <bcm/error.h> 25 #include <bcm_int/esw/mbcm.h> 26 #include <bcm_int/esw/l2.h> 27 #include <bcm_int/esw/switch.h> 28 #ifdef BCM_TOMAHAWK3_SUPPORT 29 #include <soc/tomahawk3.h> 30 #include <bcm_int/esw/tomahawk3.h> 31 32 #define GPORT_TYPE(_gport) (((_gport) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK) 33 34 #define _BCM_L2_STATION_ID_INVALID (-1) 35 #define _BCM_L2_STATION_ID_BASE (1) 36 #define _BCM_L2_STATION_ID_MAX (0x1000000) 37 38 /* To differentiate between overlay and underlay tcams */ 39 #define _BCM_L2_STATION_ENTRY_UNDERLAY (0) 40 #define _BCM_L2_STATION_ENTRY_OVERLAY (1) 41 #define _BCM_L2_STATION_ENTRY_LEGACY _BCM_L2_STATION_ENTRY_UNDERLAY 42 43 #define _BCM_L2_STATION_ENTRY_INSTALLED (1 << 0) 44 45 #define _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE (1 << 1) 46 47 #define _BCM_L2_STATION_ENTRY_TYPE_NON_TCAM (1 << 2) 48 49 #define _BCM_L2_STATION_TERM_FLAGS_MASK (BCM_L2_STATION_IPV4 \ 50 | BCM_L2_STATION_IPV6 \ 51 | BCM_L2_STATION_ARP_RARP \ 52 | BCM_L2_STATION_MPLS) 53 54 /* 55 * Macro: 56 * ParamMax 57 * Purpose: 58 * Determine maximum value that can be stored in the field. 59 */ 60 #define ParamMax(_unit_, _mem_, _field_) \ 61 ((soc_mem_field_length((_unit_), (_mem_) , (_field_)) < 32) ? \ 62 ((1 << soc_mem_field_length((_unit_), (_mem_), (_field_))) - 1) : \ 63 (0xFFFFFFFFUL)) 64 /* 65 * Macro: 66 * ParamCheck 67 * Purpose: 68 * Check if value can fit in the field and return error if it exceeds 69 * the range. 70 */ 71 #define ParamCheck(_unit_, _mem_, _field_, _value_) \ 72 do { \ 73 if (0 == ((uint32)(_value_) <= \ 74 (uint32)ParamMax((_unit_), (_mem_), (_field_)))) { \ 75 LOG_ERROR(BSL_LS_BCM_L2, \ 76 (BSL_META("L2(unit %d) Error: _value_ %d > %d (max)" \ 77 " mem (%d) field (%d).\n"), _unit_, (_value_), \ 78 (uint32)ParamMax((_unit_), (_mem_), (_field_)), \ 79 (_mem_), (_field_))); \ 80 return (BCM_E_PARAM); \ 81 } \ 82 } while(0) 83 84 /* 85 * Macro: 86 * SC_LOCK 87 * Purpose: 88 * Lock take the Field control mutex 89 */ 90 #define SC_LOCK(control) \ 91 sal_mutex_take((control)->sc_lock, sal_mutex_FOREVER) 92 93 /* 94 * Macro: 95 * SC_UNLOCK 96 * Purpose: 97 * Lock take the station control mutex 98 */ 99 #define SC_UNLOCK(control) \ 100 sal_mutex_give((control)->sc_lock); 101 102 static int th3_l2_prio_with_no_free_entries = FALSE; 103 static _bcm_l2_station_control_t *_th3_l2_station_control[BCM_MAX_NUM_UNITS] = {NULL}; 104 105 /* 106 * Function: 107 * _bcm_th3_l2_station_control_get 108 * Purpose: 109 * Get device station control structure pointer. 110 * Parameters: 111 * unit - (IN) BCM device number 112 * sc - (OUT) Device station structure pointer. 113 * Retruns: 114 * BCM_E_XXX 115 * Note: 116 * Use this function to replace _bcm_l2_station_control_get 117 */ 118 int 119 _bcm_th3_l2_station_control_get(int unit, _bcm_l2_station_control_t **sc) 120 { 121 122 /* Input parameter check */ 123 if (NULL == sc) { 124 return (BCM_E_PARAM); 125 } 126 127 if (NULL == _th3_l2_station_control[unit]) { 128 return (BCM_E_INIT); 129 } 130 131 *sc = _th3_l2_station_control[unit]; 132 133 return (BCM_E_NONE); 134 } 135 136 /* 137 * Function: 138 * _bcm_l2_station_control_deinit 139 * Purpose: 140 * Uninitialize device station control information. 141 * Parameters: 142 * unit - (IN) BCM device number 143 * Retruns: 144 * BCM_E_XXX 145 */ 146 int 147 _bcm_th3_l2_station_control_deinit(int unit) 148 { 149 _bcm_l2_station_control_t *sc; /* Station control structure pointer. */ 150 151 sc = _th3_l2_station_control[unit]; 152 if (NULL == sc) { 153 return (BCM_E_NONE); 154 } 155 156 BCM_IF_ERROR_RETURN 157 (bcm_th3_l2_station_delete_all(unit)); 158 159 if (NULL != sc->entry_arr) { 160 sal_free(sc->entry_arr); 161 sc->entry_arr = NULL; 162 } 163 164 if (NULL != sc->entry_arr_2) { 165 sal_free(sc->entry_arr_2); 166 sc->entry_arr_2 = NULL; 167 } 168 169 if (NULL != sc->sc_lock) { 170 sal_mutex_destroy(sc->sc_lock); 171 } 172 173 _th3_l2_station_control[unit] = NULL; 174 175 sal_free(sc); 176 177 return (BCM_E_NONE); 178 } 179 180 /* 181 * Function: 182 * _bcm_th3_l2_station_control_init 183 * Purpose: 184 * Initialize device station control information 185 * Parameters: 186 * unit - (IN) BCM device number 187 * Retruns: 188 * BCM_E_XXX 189 */ 190 int 191 _bcm_th3_l2_station_control_init(int unit) 192 { 193 int rv; /* Operation return status. */ 194 _bcm_l2_station_control_t *sc = NULL; /* Station control structure. */ 195 uint32 mem_size; /* Size of entry buffer. */ 196 uint32 max_entries; /* Max no. of entries in table. */ 197 int i; /* Temporary iterator variable. */ 198 199 /* Deinit if control has already been initialized. */ 200 if (NULL != _th3_l2_station_control[unit]) { 201 rv = _bcm_th3_l2_station_control_deinit(unit); 202 if (BCM_FAILURE(rv)) { 203 return (rv); 204 } 205 } 206 207 /* Allocate the station control memory for this unit. */ 208 sc = (_bcm_l2_station_control_t *) sal_alloc 209 (sizeof(_bcm_l2_station_control_t), "L2 station control"); 210 if (sc == NULL) { 211 return (BCM_E_MEMORY); 212 } 213 214 sal_memset(sc, 0, sizeof(_bcm_l2_station_control_t)); 215 216 sc->last_allocated_sid = (_BCM_L2_STATION_ID_BASE - 1); 217 218 max_entries = soc_mem_index_count(unit, MY_STATION_TCAMm); 219 220 sc->entries_total = max_entries; 221 222 sc->entries_free = max_entries; 223 224 sc->entry_count = 0; 225 226 mem_size = (max_entries * sizeof(_bcm_l2_station_entry_t *)); 227 228 sc->entry_arr = (_bcm_l2_station_entry_t **) 229 sal_alloc(mem_size, "L2 station entry pointers"); 230 if (sc->entry_arr == NULL) { 231 sal_free(sc); 232 sc = NULL; 233 return (BCM_E_MEMORY); 234 } 235 236 for (i = 0; i < max_entries; i++) { 237 sc->entry_arr[i] = NULL; 238 } 239 240 sc->sc_lock = sal_mutex_create("L2 station control.lock"); 241 if (NULL == sc->sc_lock) { 242 sal_free(sc->entry_arr); 243 sc->entry_arr = NULL; 244 sal_free(sc); 245 sc = NULL; 246 return (BCM_E_MEMORY); 247 } 248 249 _th3_l2_station_control[unit] = sc; 250 251 return (BCM_E_NONE); 252 } 253 254 STATIC int 255 _bcm_th3_l2_port_mask_gport_resolve(int unit, bcm_gport_t gport, 256 bcm_module_t *modid, bcm_port_t *port, 257 bcm_trunk_t *trunk_id, int *id) 258 { 259 int rv = SOC_E_NONE; 260 261 *modid = -1; 262 *port = -1; 263 *trunk_id = BCM_TRUNK_INVALID; 264 *id = -1; 265 266 if (SOC_GPORT_IS_TRUNK(gport)) { 267 *trunk_id = SOC_GPORT_TRUNK_GET(gport); 268 } else if (SOC_GPORT_IS_LOCAL(gport)) { 269 *modid = SOC_BASE_MODID(unit); 270 *port = SOC_GPORT_LOCAL_GET(gport); 271 } else if (SOC_GPORT_IS_MODPORT(gport)) { 272 *modid = 0; /*SOC_GPORT_MODPORT_MODID_GET(gport); should always be 0 */ 273 *port = SOC_GPORT_MODPORT_PORT_GET(gport); 274 } else { 275 rv = SOC_E_PORT; 276 } 277 278 return rv; 279 } 280 281 /* 282 * Function: 283 * _bcm_th3_l2_station_entry_set 284 * Purpose: 285 * Set a station entrie's parameters to entry buffer for hardware table 286 * write operation. 287 * Parameters: 288 * unit - (IN) BCM device number 289 * tcam_mem - (IN) Hardware memory name. 290 * station - (IN) Station parameters to be set in hardware. 291 * ent_p - (IN) Software station entry pointer. 292 * Returns: 293 * BCM_E_XXX 294 */ 295 STATIC int 296 _bcm_th3_l2_station_entry_set(int unit, 297 soc_mem_t tcam_mem, 298 bcm_l2_station_t *station, 299 _bcm_l2_station_entry_t *ent_p) 300 { 301 int gport_id = -1; 302 bcm_port_t port_out = 0; 303 bcm_module_t mod_out = 0; 304 bcm_trunk_t trunk_id = BCM_TRUNK_INVALID; 305 uint32 mod_port_data = 0; /* concatenated modid and port */ 306 bcm_port_t port_out_mask; 307 bcm_module_t mod_out_mask; 308 bcm_trunk_t trunk_id_mask = -1; 309 int gport_id_mask = -1; 310 uint32 mod_port_mask = 0; /* concatenated modid and port */ 311 int rv=0; 312 int num_bits_for_port; 313 314 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, VALIDf, 315 (1 << soc_mem_field_length(unit, tcam_mem, VALIDf)) - 1); 316 317 soc_mem_mac_addr_set(unit, tcam_mem, ent_p->tcam_ent, 318 MAC_ADDRf, station->dst_mac); 319 320 soc_mem_mac_addr_set(unit, tcam_mem, ent_p->tcam_ent, 321 MAC_ADDR_MASKf, station->dst_mac_mask); 322 323 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 324 VLAN_IDf, station->vlan); 325 326 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 327 VLAN_ID_MASKf, station->vlan_mask); 328 329 /* validate both src_port and src_port_mask has the same type */ 330 if (GPORT_TYPE(station->src_port) != GPORT_TYPE(station->src_port_mask)) { 331 return BCM_E_PARAM; 332 } 333 334 if (BCM_GPORT_IS_SET(station->src_port)) { 335 rv = _bcm_esw_gport_resolve(unit, station->src_port, 336 &mod_out, 337 &port_out, &trunk_id, 338 &gport_id); 339 BCM_IF_ERROR_RETURN(rv); 340 341 if (BCM_GPORT_IS_TRUNK(station->src_port)) { 342 if (BCM_TRUNK_INVALID == trunk_id) { 343 return BCM_E_PORT; 344 } 345 } else { 346 if ((mod_out == -1) || (port_out == -1)) { 347 return BCM_E_PORT; 348 } 349 } 350 351 /* retrieve the port mask */ 352 rv = _bcm_th3_l2_port_mask_gport_resolve(unit, 353 station->src_port_mask, 354 &mod_out_mask, 355 &port_out_mask, 356 &trunk_id_mask, 357 &gport_id_mask); 358 BCM_IF_ERROR_RETURN(rv); 359 } else { 360 port_out = station->src_port; 361 port_out_mask = station->src_port_mask; 362 mod_out = 0; 363 mod_out_mask = 0; 364 } 365 366 if (trunk_id != BCM_TRUNK_INVALID) { 367 368 /* and the SOURCE_FIELDf supports the trunk operation */ 369 SOC_IF_ERROR_RETURN(soc_mem_field32_fit(unit, tcam_mem, 370 SOURCE_FIELD_MASKf, 371 1 << SOC_TRUNK_BIT_POS(unit))); 372 373 mod_port_data = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id); 374 mod_port_mask = trunk_id_mask & 375 ((1 << SOC_TRUNK_BIT_POS(unit)) - 1); 376 mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit)); 377 378 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, SOURCE_FIELDf, 379 mod_port_data); 380 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, SOURCE_FIELD_MASKf, 381 mod_port_mask); 382 } else { 383 num_bits_for_port = _shr_popcount( 384 (unsigned int)SOC_PORT_ADDR_MAX(unit)); 385 386 mod_port_data = (mod_out << num_bits_for_port) | port_out; 387 mod_port_mask = mod_out_mask & SOC_MODID_MAX(unit); 388 mod_port_mask <<= num_bits_for_port; 389 mod_port_mask |= (port_out_mask & SOC_PORT_ADDR_MAX(unit)); 390 391 /* Clear the trunk ID bit. */ 392 mod_port_data &= ~(1 << SOC_TRUNK_BIT_POS(unit)); 393 394 /* Must match on the T bit (which should be 0) for the devices 395 * supporting the trunk operation with this field 396 */ 397 if (BCM_GPORT_IS_SET(station->src_port)) { 398 if (soc_mem_field32_fit(unit, tcam_mem, SOURCE_FIELD_MASKf, 399 1 << SOC_TRUNK_BIT_POS(unit)) == SOC_E_NONE) { 400 mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit)); 401 } 402 } 403 404 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 405 SOURCE_FIELDf, mod_port_data); 406 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 407 SOURCE_FIELD_MASKf, mod_port_mask); 408 } 409 410 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 411 MPLS_TERMINATION_ALLOWEDf, 412 ((station->flags & BCM_L2_STATION_MPLS) ? 1 : 0)); 413 414 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 415 IPV4_TERMINATION_ALLOWEDf, 416 ((station->flags & BCM_L2_STATION_IPV4) ? 1 : 0)); 417 418 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 419 IPV6_TERMINATION_ALLOWEDf, 420 ((station->flags & BCM_L2_STATION_IPV6) ? 1 : 0)); 421 422 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 423 ARP_RARP_TERMINATION_ALLOWEDf, 424 ((station->flags & BCM_L2_STATION_ARP_RARP) ? 1 : 0)); 425 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 426 COPY_TO_CPUf, 427 ((station->flags & BCM_L2_STATION_COPY_TO_CPU) 428 ? 1 : 0)); 429 430 soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, 431 DISCARDf, 432 ((station->flags & BCM_L2_STATION_DISCARD) ? 1 : 0)); 433 434 return BCM_E_NONE; 435 } 436 437 /* 438 * Function: 439 * _bcm_th3_l2_station_entry_update 440 * Purpose: 441 * Allocate an entry buffer and setup entry parameters for hardware write 442 * operation. 443 * Parameters: 444 * unit - (IN) BCM device number 445 * sid - (IN) Station ID. 446 * station - (IN) Station parameters to be set in hardware. 447 * ent_p - (OUT) Pointer to Station entry type data. 448 * Returns: 449 * BCM_E_XXX 450 */ 451 STATIC int 452 _bcm_th3_l2_station_entry_update(int unit, 453 int sid, 454 bcm_l2_station_t *station, 455 _bcm_l2_station_entry_t *ent_p) 456 { 457 soc_mem_t tcam_mem; /* TCAM memory name. */ 458 int mem_size = 0; /* Entry buffer size. */ 459 460 /* Input parameter check. */ 461 if (NULL == ent_p || NULL == station) { 462 return (BCM_E_PARAM); 463 } 464 465 LOG_DEBUG(BSL_LS_BCM_L2, 466 (BSL_META_U(unit, 467 "L2(unit %d) Info: (SID=%d) (idx=%d) (prio: o=%d n=%d) " 468 "- update.\n"), unit, sid, ent_p->hw_index, ent_p->prio, 469 station->priority)); 470 471 if (ent_p->prio == station->priority) { 472 ent_p->flags |= _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE; 473 } else { 474 ent_p->prio = station->priority; 475 } 476 477 478 tcam_mem = MY_STATION_TCAMm; 479 mem_size = sizeof(my_station_tcam_entry_t); 480 481 if (mem_size == 0) { 482 /* Must be a valid mem_size value. */ 483 return (BCM_E_INTERNAL); 484 } 485 486 ent_p->tcam_ent = sal_alloc(mem_size, "L2 station entry buffer"); 487 if (ent_p->tcam_ent == NULL) { 488 return (BCM_E_MEMORY); 489 } 490 491 sal_memset(ent_p->tcam_ent, 0, mem_size); 492 493 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_entry_set(unit, tcam_mem, 494 station, ent_p)); 495 496 return (BCM_E_NONE); 497 } 498 499 /* 500 * Function: 501 * _bcm_th3_l2_station_entry_create 502 * Purpose: 503 * Allocate an entry buffer and setup entry parameters for hardware write 504 * operation. 505 * Parameters: 506 * unit - (IN) BCM device number 507 * sid - (IN) Station ID. 508 * station - (IN) Station parameters to be set in hardware. 509 * ent_p - (OUT) Pointer to Station entry type data. 510 * Returns: 511 * BCM_E_XXX 512 */ 513 STATIC int 514 _bcm_th3_l2_station_entry_create(int unit, 515 int sid, 516 bcm_l2_station_t *station, 517 _bcm_l2_station_entry_t **ent_pp) 518 { 519 _bcm_l2_station_control_t *sc; /* Station control structure. */ 520 int index; /* Entry index. */ 521 _bcm_l2_station_entry_t *ent_p = NULL; /* L2 station entry pointer. */ 522 soc_mem_t tcam_mem; /* TCAM memory name. */ 523 int mem_size = 0; /* Entry buffer size. */ 524 int rv; /* Operation return status. */ 525 int entries_total; 526 _bcm_l2_station_entry_t **entry_arr; 527 528 /* Input parameter check. */ 529 if (NULL == station || NULL == ent_pp) { 530 return (BCM_E_PARAM); 531 } 532 533 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 534 535 if (0 == sc->entries_free) { 536 return (BCM_E_RESOURCE); 537 } 538 entry_arr = (sc->entry_arr); 539 entries_total = sc->entries_total; 540 541 ent_p = (_bcm_l2_station_entry_t *) 542 sal_alloc(sizeof(_bcm_l2_station_entry_t), "Sw L2 station entry"); 543 if (NULL == ent_p) { 544 return (BCM_E_MEMORY); 545 } 546 547 sal_memset(ent_p, 0, sizeof(_bcm_l2_station_entry_t)); 548 ent_p->sid = sid; 549 ent_p->prio = station->priority; 550 551 if (0 == sc->entries_free) { 552 sal_free(ent_p); 553 return (BCM_E_RESOURCE); 554 } 555 556 /* Get the first free slot. */ 557 for (index = 0; index < entries_total; index++) { 558 if (NULL == entry_arr[index]) { 559 ent_p->hw_index = index; 560 break; 561 } 562 } 563 564 tcam_mem = MY_STATION_TCAMm; 565 mem_size = sizeof(my_station_tcam_entry_t); 566 567 if (mem_size == 0) { 568 /* mem_size must be greater than zero. */ 569 sal_free(ent_p); 570 return (BCM_E_INTERNAL); 571 } 572 573 ent_p->tcam_ent = sal_alloc(mem_size, "L2 station entry buffer"); 574 if (NULL == ent_p->tcam_ent) { 575 sal_free(ent_p); 576 return (BCM_E_MEMORY); 577 } 578 579 sal_memset(ent_p->tcam_ent, 0, mem_size); 580 581 rv = _bcm_th3_l2_station_entry_set(unit, tcam_mem, station, ent_p); 582 if (BCM_FAILURE(rv)) { 583 sal_free(ent_p->tcam_ent); 584 sal_free(ent_p); 585 return (rv); 586 } 587 588 /* Decrement free entries count */ 589 sc->entries_free--; 590 sc->entry_count++; 591 sc->entry_arr[index] = ent_p; 592 593 *ent_pp = ent_p; 594 595 return (BCM_E_NONE); 596 597 } 598 599 /* 600 * Function: 601 * _bcm_th3_l2_station_entry_prio_cmp 602 * Purpose: 603 * Compare station entry priority values. 604 * Parameters: 605 * prio_first - (IN) First entry priority value. 606 * prio_second - (IN) Second entry priority value. 607 * Returns: 608 * 0 - if both priority values are equal. 609 * -1 - if priority value of first entry is lower than second. 610 * 1 - if priority value of first entry is greater than second. 611 */ 612 STATIC int 613 _bcm_th3_l2_station_entry_prio_cmp(int prio_first, int prio_second) 614 { 615 int rv; /* Comparison result. */ 616 617 if (prio_first == prio_second) { 618 rv = 0; 619 } else if (prio_first < prio_second) { 620 rv = -1; 621 } else { 622 rv = 1; 623 } 624 return (rv); 625 } 626 627 /* 628 * Function: 629 * _bcm_th3_l2_station_prio_move_required 630 * Purpose: 631 * Check if entry move is required based on priority value. 632 * Parameters: 633 * unit - (IN) BCM device number 634 * ent_p - (IN) Station entry for priority comparison. 635 * Returns: 636 * TRUE - Entry move is required based on priority comparison. 637 * FALSE - Entry move is not required based on priority comparison. 638 */ 639 STATIC int 640 _bcm_th3_l2_station_prio_move_required(int unit, _bcm_l2_station_entry_t *ent_p) 641 { 642 _bcm_l2_station_control_t *sc; /* station control structure. */ 643 _bcm_l2_station_entry_t **entry_arr;/* station entry array pointer */ 644 uint32 count; /* Maximum number of entries. */ 645 int i; /* Temporary iterator variable. */ 646 int ent_prio; /* Entry priority. */ 647 int flag; /* Flag value denotes if we are */ 648 /* before or after s_ent. */ 649 650 /* Input parameter check. */ 651 if (NULL == ent_p) { 652 return (BCM_E_INTERNAL); 653 } 654 655 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 656 657 /* Get total number for entries supported. */ 658 count = sc->entries_total; 659 entry_arr = (sc->entry_arr); 660 661 /* Get the entry priority value. */ 662 ent_prio = ent_p->prio; 663 664 /* Init flag value, we are before s_ent. */ 665 flag = -1; 666 667 for (i = 0; i < count; i++) { 668 669 if (entry_arr[i] == ent_p) { 670 /* Now we are after s_ent. */ 671 flag = 1; 672 continue; 673 } 674 675 if (NULL == entry_arr[i]) { 676 continue; 677 } 678 679 if (-1 == flag) { 680 if (_bcm_th3_l2_station_entry_prio_cmp(entry_arr[i]->prio, 681 ent_prio) < 0) { 682 683 LOG_DEBUG(BSL_LS_BCM_L2, 684 (BSL_META_U(unit, 685 "L2(unit %d) Info: (SID=%d) found lower prio than " 686 "(prio=%d).\n"), unit, ent_p->sid, ent_p->prio)); 687 688 /* 689 * An entry before s_ent has lower priority. 690 * So, move is required. 691 */ 692 return (TRUE); 693 } 694 } else { 695 if (_bcm_th3_l2_station_entry_prio_cmp(entry_arr[i]->prio, 696 ent_prio) > 0) { 697 LOG_DEBUG(BSL_LS_BCM_L2, 698 (BSL_META_U(unit, 699 "L2(unit %d) Info: (SID=%d) found higher prio than " 700 "(prio=%d).\n"), unit, ent_p->sid, ent_p->prio)); 701 /* 702 * An entry after s_ent has higher priority than s_ent prio. 703 * So, move is required. 704 */ 705 return (TRUE); 706 } 707 } 708 } 709 710 LOG_DEBUG(BSL_LS_BCM_L2, 711 (BSL_META_U(unit, 712 "L2(unit %d) Info: (SID=%d) (prio=%d) no move.\n"), 713 unit, ent_p->sid, ent_p->prio)); 714 715 return (FALSE); 716 } 717 718 /* 719 * Function: 720 * _bcm_th3_l2_station_entry_move_check 721 * Purpose: 722 * Calculate number of entries that need to be moved for installing the 723 * new station entry. 724 * Parameters: 725 * unit - (IN) BCM device number 726 * null_index - (IN) Free null entry hardware index. 727 * target_index - (IN) Target hardware index for the entry. 728 * direction - (IN) Direction of Move. 729 * shifted_entries_count - (OUT) No. of entries to be moved. 730 * Returns: 731 * BCM_E_NONE 732 */ 733 STATIC int 734 _bcm_th3_l2_station_entry_move_check(int unit, int null_index, 735 int target_index, int direction, 736 int *shifted_entries_count) 737 { 738 *shifted_entries_count += direction * (null_index - target_index); 739 740 return (BCM_E_NONE); 741 } 742 743 /* 744 * Function: 745 * _bcm_th3_l2_station_entry_dir_get 746 * Purpose: 747 * Find out direction in which entries need to be moved for installing 748 * new station entry in hardware. 749 * Parameters: 750 * unit - (IN) BCM device number 751 * ent_p - (IN) Station entry pointer. 752 * prev_null_index - (IN) Location of previous null entry in hardware. 753 * next_null_index - (IN) Location of next null entry in hardware. 754 * target_index - (IN) Target index where entry needs to be installed. 755 * dir - (OUT) Direction in which entries need to be moved. 756 * Returns: 757 * BCM_E_XXX 758 */ 759 STATIC int 760 _bcm_th3_l2_station_entry_dir_get(int unit, 761 _bcm_l2_station_entry_t *ent_p, 762 int prev_null_index, 763 int next_null_index, 764 int target_index, 765 int *dir) 766 { 767 _bcm_l2_station_control_t *sc; /* Station control */ 768 /* strucutre. */ 769 int shift_up = FALSE; /* Shift UP status. */ 770 int shift_down = FALSE; /* Shift DOWN status. */ 771 int shift_up_amount = 0; /* Shift UP amount. */ 772 int shift_down_amount = 0; /* Shift DOWN amount. */ 773 int rv; /* Operation return */ 774 /* status. */ 775 776 /* Input parameter check. */ 777 if (NULL == ent_p || NULL == dir) { 778 return (BCM_E_PARAM); 779 } 780 781 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 782 783 if (prev_null_index != -1) { 784 rv = _bcm_th3_l2_station_entry_move_check(unit, prev_null_index, 785 target_index, -1, 786 &shift_up_amount); 787 shift_up = BCM_SUCCESS(rv); 788 } else { 789 shift_up = FALSE; 790 } 791 792 if (next_null_index != -1) { 793 rv = _bcm_th3_l2_station_entry_move_check(unit, next_null_index, 794 target_index, 1, 795 &shift_down_amount); 796 shift_down = BCM_SUCCESS(rv); 797 } else { 798 shift_down = FALSE; 799 } 800 801 if (shift_up == TRUE) { 802 if (shift_down == TRUE) { 803 if (shift_up_amount < shift_down_amount) { 804 *dir = -1; 805 } else { 806 *dir = 1; 807 } 808 } else { 809 *dir = -1; 810 } 811 } else { 812 if (shift_down == TRUE) { 813 *dir = 1; 814 } else { 815 return FALSE; 816 } 817 } 818 return TRUE; 819 } 820 821 /* 822 * Function: 823 * _bcm_th3_l2_station_entry_move 824 * Purpose: 825 * Move a station entry by a specified amount 826 * Parameters: 827 * unit - (IN) BCM device number 828 * s_ent - (IN) Station entry pointer. 829 * amount - (IN) Direction in which entries need to be moved. 830 * Returns: 831 * BCM_E_XXX 832 */ 833 STATIC int 834 _bcm_th3_l2_station_entry_move(int unit, 835 _bcm_l2_station_entry_t *s_ent, 836 int amount) 837 { 838 _bcm_l2_station_control_t *sc; /* Station control structure. */ 839 _bcm_l2_station_entry_t **entry_arr; /* Station entry pointer . */ 840 int tcam_idx_old; /* Original entry TCAM index. */ 841 int tcam_idx_new; /* Entry new TCAM index. */ 842 int rv; /* Operation return status. */ 843 soc_mem_t tcam_mem; /* TCAM memory name. */ 844 uint32 entry[SOC_MAX_MEM_FIELD_WORDS]; /* Entry */ 845 /* buffer. */ 846 int count; 847 848 /* Input parameter check. */ 849 if (s_ent == NULL) { 850 return (BCM_E_PARAM); 851 } 852 853 /* Input parameter check. */ 854 if (amount == 0) { 855 return (BCM_E_NONE); 856 } 857 858 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 859 860 tcam_idx_old = s_ent->hw_index; 861 862 tcam_idx_new = tcam_idx_old + amount; 863 864 LOG_DEBUG(BSL_LS_BCM_L2, 865 (BSL_META_U(unit, 866 "L2(unit %d) Info: (SID=%d) move (oidx=%d nidx=%d) (amt=%d).\n"), 867 unit, s_ent->sid, s_ent->hw_index, tcam_idx_new, amount)); 868 869 count = sc->entries_total; 870 entry_arr = (sc->entry_arr); 871 872 if (tcam_idx_old < 0 || tcam_idx_old >= count) { 873 return (BCM_E_PARAM); 874 } 875 876 tcam_mem = MY_STATION_TCAMm; 877 878 if (s_ent->flags & _BCM_L2_STATION_ENTRY_INSTALLED) { 879 /* Clear entry buffer */ 880 sal_memset(entry, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 881 882 rv = soc_mem_read(unit, tcam_mem, MEM_BLOCK_ANY, tcam_idx_old, entry); 883 BCM_IF_ERROR_RETURN(rv); 884 885 rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, tcam_idx_new, entry); 886 BCM_IF_ERROR_RETURN(rv); 887 888 rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, tcam_idx_old, 889 soc_mem_entry_null(unit, tcam_mem)); 890 BCM_IF_ERROR_RETURN(rv); 891 } 892 893 if (th3_l2_prio_with_no_free_entries == FALSE) { 894 entry_arr[s_ent->hw_index] = NULL; 895 } 896 897 entry_arr[tcam_idx_new] = s_ent; 898 899 s_ent->hw_index = tcam_idx_new; 900 901 return (BCM_E_NONE); 902 } 903 904 /* 905 * Function: 906 * _bcm_th3_l2_station_entry_shift_down 907 * Purpose: 908 * Shift entries down by one index to create a free entry at target 909 * index location. 910 * Parameters: 911 * unit - (IN) BCM device number 912 * target_index - (IN) Target index for entry install operation. 913 * next_null_index - (IN) Location of free entry after target index. 914 * Returns: 915 * BCM_E_XXX 916 */ 917 STATIC int 918 _bcm_th3_l2_station_entry_shift_down(int unit, 919 int overlay, 920 int target_index, 921 int next_null_index) 922 { 923 uint16 empty_idx; /* Empty index. */ 924 _bcm_l2_station_control_t *sc; /* Station control structure. */ 925 _bcm_l2_station_entry_t **entry_arr; /* Station entry pointer */ 926 int tmp_idx1; /* Temporary index. */ 927 int tmp_idx2; /* Temporary index. */ 928 int max_entries; /* Maximum entries supported. */ 929 int rv; /* Operation return status. */ 930 931 LOG_DEBUG(BSL_LS_BCM_L2, 932 (BSL_META_U(unit, 933 "L2(unit %d) Info: Shift UP (tidx=%d null-idx=%d).\n"), 934 unit, target_index, next_null_index)); 935 936 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 937 938 empty_idx = next_null_index; 939 940 max_entries = sc->entries_total; 941 entry_arr = (sc->entry_arr); 942 943 /* 944 * Move entries one step down 945 * starting from the last entry 946 * IDEA: 947 * Move till empty_idx > target_index 948 */ 949 while (empty_idx > target_index) { 950 if (empty_idx == 0) { 951 tmp_idx1 = 0; 952 tmp_idx2 = max_entries - 1; 953 954 rv = _bcm_th3_l2_station_entry_move(unit, 955 entry_arr[max_entries - 1], 956 (tmp_idx1 - tmp_idx2)); 957 BCM_IF_ERROR_RETURN(rv); 958 } else { 959 tmp_idx1 = empty_idx; 960 tmp_idx2 = (empty_idx - 1); 961 rv = _bcm_th3_l2_station_entry_move(unit, 962 entry_arr[empty_idx - 1], 963 (tmp_idx1 - tmp_idx2)); 964 BCM_IF_ERROR_RETURN(rv); 965 966 empty_idx--; 967 } 968 } 969 970 return (BCM_E_NONE); 971 } 972 973 /* 974 * Function: 975 * _bcm_th3_l2_station_entry_shift_up 976 * Purpose: 977 * Shift entries up by one index to create a free entry at target 978 * index location. 979 * Parameters: 980 * unit - (IN) BCM device number 981 * target_index - (IN) Target index for entry install operation. 982 * prev_null_index - (IN) Location of free entry before target index. 983 * Returns: 984 * BCM_E_XXX 985 */ 986 STATIC int 987 _bcm_th3_l2_station_entry_shift_up(int unit, 988 int overlay, 989 int target_index, 990 int prev_null_index) 991 { 992 uint16 empty_idx; /* Empty index. */ 993 _bcm_l2_station_control_t *sc; /* Station control structure. */ 994 _bcm_l2_station_entry_t **entry_arr; /* Station entry pointer */ 995 int tmp_idx1; /* Temporary index. */ 996 int tmp_idx2; /* Temporary index. */ 997 int max_entries; /* Maximum entries supported. */ 998 int rv; /* Operation return status. */ 999 1000 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1001 1002 LOG_DEBUG(BSL_LS_BCM_L2, 1003 (BSL_META_U(unit, 1004 "L2(unit %d) Info: Shift UP (tidx=%d null-idx=%d).\n"), 1005 unit, target_index, prev_null_index)); 1006 1007 empty_idx = prev_null_index; 1008 1009 max_entries = sc->entries_total; 1010 entry_arr = (sc->entry_arr); 1011 1012 1013 /* 1014 * Move entries one step up 1015 * starting from the first entry 1016 * IDEA: 1017 * Move till empty_idx < target_index 1018 */ 1019 while (empty_idx < target_index) { 1020 if (empty_idx == (max_entries - 1)) { 1021 tmp_idx1 = max_entries - 1; 1022 tmp_idx2 = 0; 1023 rv = _bcm_th3_l2_station_entry_move(unit, 1024 entry_arr[0], 1025 (tmp_idx1 - tmp_idx2)); 1026 BCM_IF_ERROR_RETURN(rv); 1027 empty_idx = 0; 1028 } else { 1029 tmp_idx1 = empty_idx; 1030 tmp_idx2 = (empty_idx + 1); 1031 rv = _bcm_th3_l2_station_entry_move(unit, 1032 entry_arr[empty_idx + 1], 1033 (tmp_idx1 - tmp_idx2)); 1034 BCM_IF_ERROR_RETURN(rv); 1035 1036 empty_idx++; 1037 } 1038 } 1039 1040 return (BCM_E_NONE); 1041 } 1042 1043 /* 1044 * Function: 1045 * _bcm_th3_l2_station_entry_install 1046 * Purpose: 1047 * Write a station entry to hardware 1048 * Parameters: 1049 * unit - (IN) BCM device number 1050 * ent_p - (IN) Pointer to station entry. 1051 * Returns: 1052 * BCM_E_XXX 1053 */ 1054 STATIC int 1055 _bcm_th3_l2_station_entry_install(int unit, _bcm_l2_station_entry_t *ent_p) 1056 { 1057 int rv; /* Operation return status. */ 1058 soc_mem_t tcam_mem; /* TCAM memory name. */ 1059 1060 if (ent_p == NULL) { 1061 return (BCM_E_PARAM); 1062 } 1063 1064 tcam_mem = MY_STATION_TCAMm; 1065 1066 if (ent_p->tcam_ent == NULL) { 1067 return (BCM_E_INTERNAL); 1068 } 1069 1070 LOG_DEBUG(BSL_LS_BCM_L2, 1071 (BSL_META_U(unit, 1072 "L2(unit %d) Info: (SID=%d) - install (idx=%d).\n"), 1073 unit, ent_p->sid, ent_p->hw_index)); 1074 1075 rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, ent_p->hw_index, 1076 ent_p->tcam_ent); 1077 1078 sal_free(ent_p->tcam_ent); 1079 1080 ent_p->tcam_ent = NULL; 1081 1082 return (rv); 1083 } 1084 1085 1086 /* 1087 * Function: 1088 * _bcm_th3_l2_station_entry_prio_install 1089 * Purpose: 1090 * Install an entry based on priority value. 1091 * Parameters: 1092 * unit - (IN) BCM device number 1093 * ent_p - (IN) Pointer to station entry. 1094 * Returns: 1095 * BCM_E_XXX 1096 */ 1097 STATIC int 1098 _bcm_th3_l2_station_entry_prio_install(int unit, _bcm_l2_station_entry_t *ent_p) 1099 { 1100 _bcm_l2_station_control_t *sc; /* Control structure. */ 1101 _bcm_l2_station_entry_t **entry_arr; /* L2 station entry */ 1102 int idx_old; /* Entry old TCAM index. */ 1103 int idx_target; /* Entry target index. */ 1104 int prev_null_idx = -1; /* Prev NULL entry index. */ 1105 int next_null_idx = -1; /* Next NULL entry index. */ 1106 int temp; /* Temporary variable. */ 1107 int dir = -1; /* -1 = UP, 1 = DOWN */ 1108 int decr_on_shift_up = TRUE; /* Shift up status */ 1109 int rv; /* Return status. */ 1110 int flag_no_free_entries = FALSE; /* No free */ 1111 /* entries status */ 1112 int max_entries; 1113 int free_entries; 1114 int overlay; 1115 th3_l2_prio_with_no_free_entries = FALSE; 1116 1117 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1118 1119 1120 if ((ent_p->flags & _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE) 1121 || (_bcm_th3_l2_station_prio_move_required(unit, ent_p) == FALSE)) { 1122 goto end; 1123 } 1124 1125 idx_old = ent_p->hw_index; 1126 1127 overlay = _BCM_L2_STATION_ENTRY_UNDERLAY; 1128 max_entries = sc->entries_total; 1129 entry_arr = (sc->entry_arr); 1130 free_entries = sc->entries_free; 1131 1132 if (idx_old >= max_entries) { 1133 return (BCM_E_INTERNAL); 1134 } 1135 1136 if (free_entries == 0) { 1137 if ((ent_p->flags & _BCM_L2_STATION_ENTRY_INSTALLED) == 0) { 1138 entry_arr[ent_p->hw_index] = NULL; 1139 flag_no_free_entries = TRUE; 1140 } else { 1141 return (BCM_E_CONFIG); 1142 } 1143 } 1144 1145 for (idx_target = 0; idx_target < max_entries; idx_target++) { 1146 1147 /* Skip the entry itself. */ 1148 if (ent_p == entry_arr[idx_target]) { 1149 continue; 1150 } 1151 1152 if (NULL == entry_arr[idx_target]) { 1153 /* Store the null slot index. */ 1154 prev_null_idx = idx_target; 1155 continue; 1156 } 1157 1158 if (_bcm_th3_l2_station_entry_prio_cmp(ent_p->prio, 1159 entry_arr[idx_target]->prio) > 0) { 1160 /* Found the entry with priority lower than ent_p prio. */ 1161 break; 1162 } 1163 } 1164 1165 temp = idx_target; 1166 1167 if (idx_target != (max_entries - 1)) { 1168 /* Find next empty slot after ent_p. */ 1169 for (; temp < max_entries; temp++) { 1170 if (entry_arr[temp] == NULL) { 1171 next_null_idx = temp; 1172 break; 1173 } 1174 } 1175 } 1176 1177 /* Put the entry back. */ 1178 if (flag_no_free_entries == TRUE) { 1179 entry_arr[ent_p->hw_index] = ent_p; 1180 } 1181 1182 /* No empty slot found. */ 1183 if (prev_null_idx == -1 && next_null_idx == -1) { 1184 return (BCM_E_CONFIG); 1185 } 1186 1187 if (idx_target == max_entries) { 1188 /* Target location is after the last installed entry. */ 1189 if (prev_null_idx == (max_entries - 1)) { 1190 idx_target = prev_null_idx; 1191 goto only_move; 1192 } else { 1193 idx_target = (max_entries - 1); 1194 decr_on_shift_up = FALSE; 1195 } 1196 } 1197 1198 if (_bcm_th3_l2_station_entry_dir_get(unit, 1199 ent_p, 1200 prev_null_idx, 1201 next_null_idx, 1202 idx_target, 1203 &dir) == FALSE) { 1204 return (BCM_E_PARAM); 1205 } 1206 1207 if (dir == 1) { 1208 /* 1209 * Move the entry at the target index to target_index+1. This may 1210 * mean shifting more entries down to make room. In other words, 1211 * shift the target index and any that follow it down 1 as far as the 1212 * next empty index. 1213 */ 1214 if (entry_arr[idx_target] != NULL) { 1215 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_entry_shift_down(unit, 1216 overlay, idx_target, next_null_idx)); 1217 } 1218 } else { 1219 if (decr_on_shift_up == TRUE) { 1220 idx_target--; 1221 LOG_DEBUG(BSL_LS_BCM_L2, 1222 (BSL_META_U(unit, 1223 "L2(unit %d) Info: Decr. on Shift UP (idx_tgt=%d).\n"), 1224 unit, idx_target)); 1225 } 1226 1227 if (entry_arr[idx_target] != NULL) { 1228 /* coverity[negative_returns] */ 1229 BCM_IF_ERROR_RETURN (_bcm_th3_l2_station_entry_shift_up(unit, 1230 overlay, idx_target, prev_null_idx)); 1231 } 1232 } 1233 1234 /* Move the entry from old index to new index. */ 1235 only_move: 1236 if ((idx_target - ent_p->hw_index) != 0) { 1237 1238 if (flag_no_free_entries == TRUE) { 1239 th3_l2_prio_with_no_free_entries = TRUE; 1240 } 1241 1242 rv = _bcm_th3_l2_station_entry_move(unit, ent_p, 1243 (idx_target - ent_p->hw_index)); 1244 1245 if (BCM_FAILURE(rv)) { 1246 th3_l2_prio_with_no_free_entries = FALSE; 1247 return (rv); 1248 } 1249 1250 th3_l2_prio_with_no_free_entries = FALSE; 1251 } 1252 1253 end: 1254 1255 ent_p->flags &= ~_BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE; 1256 1257 rv = _bcm_th3_l2_station_entry_install(unit, ent_p); 1258 if (BCM_FAILURE(rv)) { 1259 return rv; 1260 } 1261 return (BCM_E_NONE); 1262 } 1263 1264 /* 1265 * Function: 1266 * _bcm_th3_l2_station_entry_get 1267 * Purpose: 1268 * Get station entry details by performing 1269 * lookup using station ID. 1270 * Parameters: 1271 * unit - (IN) BCM device number 1272 * sid - (IN) Station ID. 1273 * ent_p - (OUT) Station look up result. 1274 * Retruns: 1275 * BCM_E_XXX 1276 */ 1277 int 1278 _bcm_th3_l2_station_entry_get(int unit, 1279 int sid, 1280 _bcm_l2_station_entry_t **ent_p) 1281 { 1282 _bcm_l2_station_control_t *sc; /* Station control structure pointer. */ 1283 _bcm_l2_station_entry_t **entry_arr; 1284 int index; /* Entry index. */ 1285 int count; 1286 /* Input parameter check. */ 1287 if (ent_p == NULL) { 1288 return (BCM_E_PARAM); 1289 } 1290 1291 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1292 1293 count = sc->entries_total; 1294 entry_arr = (sc->entry_arr); 1295 1296 for (index = 0; index < count; index++) { 1297 1298 if (entry_arr[index] == NULL) { 1299 continue; 1300 } 1301 1302 if (sid == entry_arr[index]->sid) { 1303 *ent_p = entry_arr[index]; 1304 LOG_DEBUG(BSL_LS_BCM_L2, 1305 (BSL_META_U(unit, 1306 "L2(unit %d) Info: (SID=%d) - found (idx=%d).\n"), 1307 unit, sid, index)); 1308 return (BCM_E_NONE); 1309 } 1310 } 1311 1312 LOG_DEBUG(BSL_LS_BCM_L2, 1313 (BSL_META_U(unit, 1314 "L2(unit %d) Info: (SID=%d) - not found (idx=%d).\n"), 1315 unit, sid, index)); 1316 1317 /* L2 station entry with ID == sid not found. */ 1318 return (BCM_E_NOT_FOUND); 1319 } 1320 1321 /* 1322 * Function: 1323 * _bcm_th3_l2_station_param_check 1324 * Purpose: 1325 * Validate L2 station user input parameters. 1326 * Parameters: 1327 * unit - (IN) BCM device number 1328 * station - (IN) Station information for lookup by hardware. 1329 * station_id - (IN) Station entry ID. 1330 * Returns: 1331 * BCM_E_XXX 1332 */ 1333 STATIC int 1334 _bcm_th3_l2_station_param_check(int unit, bcm_l2_station_t *station, 1335 int station_id) 1336 { 1337 soc_mem_t tcam_mem; /* Hardware table name. */ 1338 bcm_gport_t gport_id; 1339 bcm_port_t port_out; 1340 bcm_module_t mod_out; 1341 bcm_trunk_t trunk_id; 1342 uint32 mod_port_data = 0; /* concatenated modid and port */ 1343 int num_bits_for_port; 1344 1345 /* Input parameter check. */ 1346 if (NULL == station) { 1347 return (BCM_E_PARAM); 1348 } 1349 1350 if (station->flags & BCM_L2_STATION_FCOE) { 1351 /* FCoE Termination is not supported */ 1352 return (BCM_E_UNAVAIL); 1353 } 1354 1355 if (station->flags & BCM_L2_STATION_OAM) { 1356 return (BCM_E_UNAVAIL); 1357 } 1358 1359 1360 tcam_mem = MY_STATION_TCAMm; 1361 ParamCheck(unit, tcam_mem, VLAN_IDf, station->vlan); 1362 ParamCheck(unit, tcam_mem, VLAN_ID_MASKf, station->vlan_mask); 1363 1364 if (GPORT_TYPE(station->src_port) != GPORT_TYPE(station->src_port_mask)) { 1365 return BCM_E_PARAM; 1366 } 1367 num_bits_for_port = _shr_popcount( 1368 (unsigned int)SOC_PORT_ADDR_MAX(unit)); 1369 if (BCM_GPORT_IS_SET(station->src_port)) { 1370 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, 1371 station->src_port, 1372 &mod_out, 1373 &port_out, &trunk_id, 1374 &gport_id)); 1375 if (BCM_GPORT_IS_TRUNK(station->src_port)) { 1376 if (BCM_TRUNK_INVALID == trunk_id) { 1377 return BCM_E_PORT; 1378 } 1379 1380 mod_port_data = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id); 1381 } else { 1382 if ((-1 == mod_out) || (-1 == port_out)) { 1383 return BCM_E_PORT; 1384 } 1385 mod_port_data = (mod_out << num_bits_for_port) | port_out; 1386 } 1387 } else { 1388 int my_modid; 1389 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit,&my_modid)); 1390 port_out = station->src_port; 1391 mod_port_data = station->src_port | 1392 (my_modid << num_bits_for_port); 1393 } 1394 1395 if (SOC_MEM_FIELD_VALID(unit, tcam_mem, SOURCE_FIELDf)) { 1396 ParamCheck(unit, tcam_mem, SOURCE_FIELDf, mod_port_data); 1397 } else { 1398 ParamCheck(unit, tcam_mem, ING_PORT_NUMf, port_out); 1399 } 1400 1401 return (BCM_E_NONE); 1402 } 1403 1404 /* 1405 * Function: 1406 * bcm_th3_l2_station_add 1407 * Purpose: 1408 * Create an entry with specified ID or generated ID and install 1409 * the entry in hardware. 1410 * Parameters: 1411 * unit - (IN) BCM device number 1412 * station_id - (IN/OUT) Station entry ID. 1413 * station - (IN) Station information for lookup by hardware. 1414 * Returns: 1415 * BCM_E_XXX 1416 */ 1417 int 1418 bcm_th3_l2_station_add(int unit, 1419 int *station_id, 1420 bcm_l2_station_t *station) 1421 { 1422 _bcm_l2_station_control_t *sc; /* Control structure. */ 1423 _bcm_l2_station_entry_t *ent = NULL; /* Entry pointer. */ 1424 int rv; /* Operation return status. */ 1425 int sid = -1; /* Entry ID. */ 1426 1427 /* Input parameter check. */ 1428 if (NULL == station || NULL == station_id) { 1429 return (BCM_E_PARAM); 1430 } 1431 1432 /* ID needs to be passed for replace operation. */ 1433 if ((station->flags & BCM_L2_STATION_REPLACE) 1434 && !(station->flags & BCM_L2_STATION_WITH_ID)) { 1435 return (BCM_E_PARAM); 1436 } 1437 1438 rv = _bcm_th3_l2_station_param_check(unit, station, *station_id); 1439 if (BCM_FAILURE(rv)) { 1440 return (BCM_E_PARAM); 1441 } 1442 1443 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1444 1445 SC_LOCK(sc); 1446 1447 if (station->flags & BCM_L2_STATION_WITH_ID) { 1448 if ((sc->last_allocated_sid < *station_id) && 1449 (*station_id <= _BCM_L2_STATION_ID_MAX)) { 1450 sc->last_allocated_sid = *station_id; 1451 } 1452 sid = *station_id; 1453 } else { 1454 sid = ++sc->last_allocated_sid; 1455 1456 if (_BCM_L2_STATION_ID_MAX < sid) { 1457 sc->last_allocated_sid = _BCM_L2_STATION_ID_MAX; 1458 1459 for (sid = _BCM_L2_STATION_ID_BASE; 1460 sid <= _BCM_L2_STATION_ID_MAX; sid++) { 1461 if (BCM_E_NOT_FOUND == 1462 _bcm_th3_l2_station_entry_get(unit, sid, &ent)) { 1463 break; 1464 } 1465 } 1466 } 1467 1468 *station_id = sid; 1469 } 1470 1471 rv = _bcm_th3_l2_station_entry_get(unit, sid, &ent); 1472 1473 /* For replace operation, entry must exist. */ 1474 if (BCM_FAILURE(rv) 1475 && (station->flags & BCM_L2_STATION_REPLACE)) { 1476 LOG_ERROR(BSL_LS_BCM_L2, 1477 (BSL_META_U(unit, 1478 "L2(unit %d) Error: Replace (SID=%d) - Invalid (%s).\n"), 1479 unit, sid, bcm_errmsg(rv))); 1480 SC_UNLOCK(sc); 1481 return (rv); 1482 } 1483 1484 /* For non-replace operations, entry must not exist. */ 1485 if (BCM_SUCCESS(rv) 1486 && (0 == (station->flags & BCM_L2_STATION_REPLACE))) { 1487 LOG_INFO(BSL_LS_BCM_L2, 1488 (BSL_META_U(unit, 1489 "L2(unit %d) Error: (SID=%d) add - failed (%s).\n"), 1490 unit, sid, bcm_errmsg(rv))); 1491 SC_UNLOCK(sc); 1492 return (BCM_E_EXISTS); 1493 } 1494 1495 if (0 == (station->flags & BCM_L2_STATION_REPLACE)) { 1496 rv = _bcm_th3_l2_station_entry_create(unit, sid, station, &ent); 1497 if (BCM_FAILURE(rv)) { 1498 LOG_INFO(BSL_LS_BCM_L2, 1499 (BSL_META_U(unit, 1500 "L2(unit %d) Error: Station (SID=%d) add - failed (%s).\n"), 1501 unit, sid, bcm_errmsg(rv))); 1502 SC_UNLOCK(sc); 1503 return (rv); 1504 } 1505 } else { 1506 rv = _bcm_th3_l2_station_entry_update(unit, sid, station, ent); 1507 if (BCM_FAILURE(rv)) { 1508 LOG_ERROR(BSL_LS_BCM_L2, 1509 (BSL_META_U(unit, 1510 "L2(unit %d) Error: Station (SID=%d) update - failed (%s).\n"), 1511 unit, sid, bcm_errmsg(rv))); 1512 SC_UNLOCK(sc); 1513 return (rv); 1514 } 1515 } 1516 1517 rv = _bcm_th3_l2_station_entry_prio_install(unit, ent); 1518 if (BCM_FAILURE(rv)) { 1519 if (NULL != ent->tcam_ent) { 1520 sal_free(ent->tcam_ent); 1521 } 1522 LOG_ERROR(BSL_LS_BCM_L2, 1523 (BSL_META_U(unit, 1524 "L2(unit %d) Error: (SID=%d) install - failed (%s).\n"), 1525 unit, sid, bcm_errmsg(rv))); 1526 SC_UNLOCK(sc); 1527 return (rv); 1528 } 1529 1530 /* Mark the entry as installed. */ 1531 ent->flags |= _BCM_L2_STATION_ENTRY_INSTALLED; 1532 1533 SC_UNLOCK(sc); 1534 return (rv); 1535 } 1536 1537 /* 1538 * Function: 1539 * bcm_th3_l2_station_delete 1540 * Purpose: 1541 * Deallocate the memory used to track an entry and remove the entry 1542 * from hardware 1543 * Parameters: 1544 * unit - (IN) BCM device number 1545 * station_id - (IN) Station entry ID 1546 * Returns: 1547 * BCM_E_XXX 1548 */ 1549 int 1550 bcm_th3_l2_station_delete(int unit, int station_id) 1551 { 1552 _bcm_l2_station_entry_t *s_ent = NULL; /* Entry pointer. */ 1553 _bcm_l2_station_entry_t **entry_arr = NULL; /* Entry pointer. */ 1554 _bcm_l2_station_control_t *sc = NULL; /* Control structure. */ 1555 int rv; /* Operation return status. */ 1556 soc_mem_t tcam_mem; /* TCMA memory name. */ 1557 1558 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1559 1560 SC_LOCK(sc); 1561 1562 /* Get the entry by ID. */ 1563 rv = _bcm_th3_l2_station_entry_get(unit, station_id, &s_ent); 1564 if (BCM_FAILURE(rv)) { 1565 SC_UNLOCK(sc); 1566 return (rv); 1567 } 1568 1569 entry_arr = (sc->entry_arr); 1570 1571 tcam_mem = MY_STATION_TCAMm; 1572 1573 /* Remove the entry from hardware by clearing the index. */ 1574 rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, s_ent->hw_index, 1575 soc_mem_entry_null(unit, tcam_mem)); 1576 if (BCM_FAILURE(rv)) { 1577 SC_UNLOCK(sc); 1578 return (rv); 1579 } 1580 1581 /* Free tcam buffer. */ 1582 if (NULL != s_ent->tcam_ent) { 1583 sal_free(s_ent->tcam_ent); 1584 } 1585 1586 /* Remove the entry pointer from the list. */ 1587 entry_arr[s_ent->hw_index] = NULL; 1588 1589 /* Increment free entries count. */ 1590 sc->entries_free++; 1591 sc->entry_count--; 1592 1593 /* Free the entry. */ 1594 sal_free(s_ent); 1595 1596 /* Rset the last_allocated_sid */ 1597 if (station_id == sc->last_allocated_sid) { 1598 --sc->last_allocated_sid; 1599 } 1600 1601 SC_UNLOCK(sc); 1602 1603 return (rv); 1604 } 1605 1606 /* 1607 * Function: 1608 * _bcm_th3_l2_station_entry_delete_all 1609 * Purpose: 1610 * Deallocate all memory used to track entries and remove entries from 1611 * hardware. 1612 * Parameters: 1613 * unit - (IN) BCM device number 1614 * overlay - (IN) Overlay/Underlay identification 1615 * Returns: 1616 * BCM_E_XXX 1617 */ 1618 STATIC int 1619 _bcm_th3_l2_station_entry_delete_all(int unit, int overlay) 1620 { 1621 _bcm_l2_station_control_t *sc = NULL; /* Control strucutre. */ 1622 _bcm_l2_station_entry_t **entry_arr = NULL; /* Entry array. */ 1623 int rv; /* Operation return status. */ 1624 int index; /* Entry index. */ 1625 int max_entries; 1626 1627 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1628 1629 SC_LOCK(sc); 1630 1631 max_entries = (overlay == _BCM_L2_STATION_ENTRY_OVERLAY) ? 1632 sc->entries_total_2 : sc->entries_total; 1633 entry_arr = (overlay == _BCM_L2_STATION_ENTRY_OVERLAY) ? 1634 (sc->entry_arr_2) : (sc->entry_arr); 1635 1636 if (NULL == entry_arr) { 1637 SC_UNLOCK(sc); 1638 return (BCM_E_NONE); 1639 } 1640 1641 for (index = 0; index < max_entries; index++) { 1642 1643 if (NULL == entry_arr[index]) { 1644 continue; 1645 } 1646 1647 rv = bcm_th3_l2_station_delete(unit, entry_arr[index]->sid); 1648 1649 if (BCM_FAILURE(rv)) { 1650 SC_UNLOCK(sc); 1651 return (rv); 1652 } 1653 } 1654 1655 SC_UNLOCK(sc); 1656 1657 return (BCM_E_NONE); 1658 } 1659 1660 /* 1661 * Function: 1662 * bcm_th3_l2_station_delete_all 1663 * Purpose: 1664 * Deallocate all memory used to track entries and remove entries from 1665 * hardware. 1666 * Parameters: 1667 * unit - (IN) BCM device number 1668 * Returns: 1669 * BCM_E_XXX 1670 */ 1671 int 1672 bcm_th3_l2_station_delete_all(int unit) 1673 { 1674 int rv; 1675 1676 rv = _bcm_th3_l2_station_entry_delete_all(unit, 1677 _BCM_L2_STATION_ENTRY_UNDERLAY); 1678 1679 return rv; 1680 } 1681 1682 /* 1683 * Function: 1684 * bcm_th3_l2_station_get 1685 * Purpose: 1686 * Get station information for a given station ID. 1687 * Parameters: 1688 * unit - (IN) BCM device number 1689 * station_id - (IN) Station entry ID. 1690 * station - (OUT) Station entry lookup information. 1691 * Returns: 1692 * BCM_E_XXX 1693 */ 1694 int 1695 bcm_th3_l2_station_get(int unit, int station_id, bcm_l2_station_t *station) 1696 { 1697 _bcm_l2_station_entry_t *s_ent = NULL; /* Entry pointer */ 1698 _bcm_l2_station_control_t *sc = NULL; /* Control structure */ 1699 int rv; /* Operation return status */ 1700 soc_mem_t tcam_mem; /* TCAM memory name */ 1701 uint32 entry[SOC_MAX_MEM_FIELD_WORDS]; /* Entry */ 1702 /* buffer */ 1703 int src_field; 1704 int src_mask_field; 1705 _bcm_gport_dest_t src; 1706 _bcm_gport_dest_t src_mask; 1707 int num_bits_for_port; 1708 1709 /* Input parameter check. */ 1710 if (station == NULL) { 1711 return (BCM_E_PARAM); 1712 } 1713 1714 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1715 SC_LOCK(sc); 1716 1717 /* Get the entry by ID. */ 1718 rv = _bcm_th3_l2_station_entry_get(unit, station_id, &s_ent); 1719 if (BCM_FAILURE(rv)) { 1720 SC_UNLOCK(sc); 1721 return (rv); 1722 } 1723 1724 tcam_mem = MY_STATION_TCAMm; 1725 1726 /* Clear entry buffer. */ 1727 sal_memset(entry, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 1728 1729 rv = soc_mem_read(unit, tcam_mem, MEM_BLOCK_ANY, s_ent->hw_index, entry); 1730 if (BCM_FAILURE(rv)) { 1731 SC_UNLOCK(sc); 1732 return (rv); 1733 } 1734 1735 station->priority = s_ent->prio; 1736 1737 soc_mem_mac_addr_get(unit, tcam_mem, entry, 1738 MAC_ADDRf, station->dst_mac); 1739 1740 soc_mem_mac_addr_get(unit, tcam_mem, entry, 1741 MAC_ADDR_MASKf, station->dst_mac_mask); 1742 1743 station->vlan = soc_mem_field32_get(unit, tcam_mem, entry, VLAN_IDf); 1744 1745 station->vlan_mask = soc_mem_field32_get(unit, tcam_mem, entry, 1746 VLAN_ID_MASKf); 1747 1748 _bcm_gport_dest_t_init(&src); 1749 _bcm_gport_dest_t_init(&src_mask); 1750 1751 src_field= soc_mem_field32_get(unit, tcam_mem, entry, 1752 SOURCE_FIELDf); 1753 src_mask_field = soc_mem_field32_get(unit, tcam_mem, entry, 1754 SOURCE_FIELD_MASKf); 1755 1756 if ((src_field >> SOC_TRUNK_BIT_POS(unit)) & 0x1) { 1757 src.tgid = src_field & ((1 << SOC_TRUNK_BIT_POS(unit)) - 1); 1758 src.gport_type = _SHR_GPORT_TYPE_TRUNK; 1759 src_mask.tgid = src_mask_field & 1760 ((1 << SOC_TRUNK_BIT_POS(unit)) - 1); 1761 src_mask.gport_type = _SHR_GPORT_TYPE_TRUNK; 1762 } else { 1763 src.port = src_field & SOC_PORT_ADDR_MAX(unit); 1764 src.modid = (src_field - src.port) / 1765 (SOC_PORT_ADDR_MAX(unit) + 1); 1766 src.gport_type = _SHR_GPORT_TYPE_MODPORT; 1767 num_bits_for_port = _shr_popcount( 1768 (unsigned int)SOC_PORT_ADDR_MAX(unit)); 1769 src_mask.port = src_mask_field & SOC_PORT_ADDR_MAX(unit); 1770 src_mask.gport_type = _SHR_GPORT_TYPE_MODPORT; 1771 src_mask.modid = (src_mask_field >> num_bits_for_port) & 1772 SOC_MODID_MAX(unit); 1773 } 1774 1775 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &src, 1776 &(station->src_port))); 1777 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &src_mask, 1778 &(station->src_port_mask))); 1779 1780 if (soc_mem_field32_get(unit, tcam_mem, entry, 1781 MPLS_TERMINATION_ALLOWEDf)) { 1782 station->flags |= BCM_L2_STATION_MPLS; 1783 } 1784 1785 if (soc_mem_field32_get(unit, tcam_mem, entry, 1786 IPV4_TERMINATION_ALLOWEDf)) { 1787 station->flags |= BCM_L2_STATION_IPV4; 1788 } 1789 1790 if (soc_mem_field32_get(unit, tcam_mem, entry, 1791 IPV6_TERMINATION_ALLOWEDf)) { 1792 station->flags |= BCM_L2_STATION_IPV6; 1793 } 1794 1795 if (soc_mem_field32_get(unit, tcam_mem, entry, 1796 ARP_RARP_TERMINATION_ALLOWEDf)) { 1797 station->flags |= BCM_L2_STATION_ARP_RARP; 1798 } 1799 1800 if (soc_mem_field32_get(unit, tcam_mem, entry, 1801 COPY_TO_CPUf)) { 1802 station->flags |= BCM_L2_STATION_COPY_TO_CPU; 1803 } 1804 1805 if (soc_mem_field32_get(unit, tcam_mem, entry, DISCARDf)) { 1806 station->flags |= BCM_L2_STATION_DISCARD; 1807 } 1808 1809 SC_UNLOCK(sc); 1810 1811 return (rv); 1812 } 1813 1814 /* 1815 * Function: 1816 * bcm_th3_l2_station_size_get 1817 * Purpose: 1818 * Get number of entries supported by L2 station API 1819 * Parameters: 1820 * unit - (IN) BCM device number 1821 * size - (OUT) Station entry ID 1822 * Returns: 1823 * BCM_E_XXX 1824 */ 1825 int 1826 bcm_th3_l2_station_size_get(int unit, int *size) 1827 { 1828 _bcm_l2_station_control_t *sc = NULL; /* Station control structure. */ 1829 1830 /* Input parameter check */ 1831 if (size == NULL) { 1832 return (BCM_E_PARAM); 1833 } 1834 1835 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1836 SC_LOCK(sc); 1837 1838 *size = sc->entries_total; 1839 1840 SC_UNLOCK(sc); 1841 1842 return (BCM_E_NONE); 1843 } 1844 1845 /* 1846 * Function: 1847 * _bcm_th3_l2_station_entry_last_sid_set 1848 * Purpose: 1849 * Set the current last station id for L2 station. 1850 * Parameters: 1851 * unit - (IN) BCM device number 1852 * overlay - (IN) Overlay/Underlay identification (not used in the rev) 1853 * sid - (IN) Station ID. 1854 * Returns: 1855 * BCM_E_XXX 1856 */ 1857 int 1858 _bcm_th3_l2_station_entry_last_sid_set(int unit, int overlay, int sid) 1859 { 1860 _bcm_l2_station_control_t *sc = NULL; 1861 1862 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1863 1864 if (sid) { 1865 sc->last_allocated_sid = sid; 1866 } else { 1867 sc->last_allocated_sid = _BCM_L2_STATION_ID_BASE - 1; 1868 } 1869 1870 return BCM_E_NONE; 1871 } 1872 1873 /* 1874 * Function: 1875 * bcm_th3_l2_station_traverse 1876 * Purpose: 1877 * Walk through station entries and executed user supplied callback function 1878 * Parameters: 1879 * unit - (IN) BCM device number 1880 * trav_fn - (IN) Caller supplied function to execute for each entry 1881 * user_data - (IN) Argument list for the callback function 1882 * Returns: 1883 * BCM_E_XXX 1884 */ 1885 int 1886 bcm_th3_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn, 1887 void *user_data) 1888 { 1889 _bcm_l2_station_control_t *sc = NULL; /* Station control structure */ 1890 int index; /* Entry index */ 1891 int count; 1892 int rv = BCM_E_NONE; 1893 _bcm_l2_station_entry_t *s_ent = NULL; 1894 bcm_l2_station_t l2_station; 1895 int station_id; 1896 1897 /* Input parameter check */ 1898 if (!trav_fn) { 1899 return BCM_E_PARAM; 1900 } 1901 1902 memset((void *)(&l2_station), 0, sizeof(bcm_l2_station_t)); 1903 1904 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1905 1906 count = sc->entries_total; 1907 1908 for (index = 0; index < count; index++) { 1909 1910 s_ent = sc->entry_arr[index]; /* H/W index */ 1911 1912 if (s_ent == NULL) { 1913 continue; 1914 } 1915 1916 station_id = sc->entry_arr[index]->sid; /* Get S/W handle */ 1917 1918 rv = bcm_th3_l2_station_get(unit, station_id, &l2_station); 1919 1920 if (BCM_FAILURE(rv)) { 1921 break; 1922 } 1923 1924 rv = trav_fn(unit, &l2_station, user_data); 1925 1926 if (BCM_FAILURE(rv)) { 1927 LOG_DEBUG(BSL_LS_BCM_L2, 1928 (BSL_META_U(unit, 1929 "L2(unit %d) Info: Traverse (SID=%d)/(idx=%d) entry failed.\n"), 1930 unit, station_id, index)); 1931 break; 1932 } 1933 } 1934 1935 return rv; 1936 } 1937 1938 #ifdef BCM_WARM_BOOT_SUPPORT 1939 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */ 1940 /* 1941 * Function: 1942 * _bcm_th3_l2_station_entry_reload 1943 * Purpose: 1944 * Re-construct L2 station control structure software state 1945 * from installed hardware entries 1946 * Parameters: 1947 * unit - (IN) BCM device number 1948 * Returns: 1949 * BCM_E_XXX 1950 */ 1951 STATIC int 1952 _bcm_th3_l2_station_entry_reload(int unit, int overlay) 1953 { 1954 _bcm_l2_station_control_t *sc; /* Pointer to station */ 1955 /* control structure. */ 1956 int rv; /* Operation return status. */ 1957 uint32 *tcam_buf = NULL; /* Buffer to store TCAM */ 1958 /* table entries. */ 1959 int entry_mem_size; /* Size of TCAM table entry. */ 1960 int index; /* Table index iterator. */ 1961 _bcm_l2_station_entry_t *s_ent_p; /* Station table entry. */ 1962 my_station_tcam_entry_t *my_station_ent; /* Table entry pointer. */ 1963 1964 1965 entry_mem_size = sizeof(my_station_tcam_entry_t); 1966 1967 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc)); 1968 1969 SC_LOCK(sc); 1970 1971 /* Allocate buffer to store the DMAed table entries. */ 1972 tcam_buf = soc_cm_salloc(unit, entry_mem_size * sc->entries_total, 1973 "STATION TCAM buffer"); 1974 if (NULL == tcam_buf) { 1975 SC_UNLOCK(sc); 1976 return (BCM_E_MEMORY); 1977 } 1978 /* Initialize the entry buffer. */ 1979 sal_memset(tcam_buf, 0, entry_mem_size * sc->entries_total); 1980 1981 /* Read the table entries into the buffer. */ 1982 rv = soc_mem_read_range(unit, MY_STATION_TCAMm, MEM_BLOCK_ALL, 1983 0, (sc->entries_total - 1), tcam_buf); 1984 if (BCM_FAILURE(rv)) { 1985 goto cleanup; 1986 } 1987 1988 /* Iterate over the table entries. */ 1989 for (index = 0; index < sc->entries_total; index++) { 1990 1991 my_station_ent = soc_mem_table_idx_to_pointer(unit, MY_STATION_TCAMm, 1992 my_station_tcam_entry_t *, tcam_buf, index); 1993 1994 if (0 == soc_MY_STATION_TCAMm_field32_get(unit, my_station_ent, 1995 VALIDf)) { 1996 continue; 1997 } 1998 1999 s_ent_p = (_bcm_l2_station_entry_t *)sal_alloc( 2000 sizeof(_bcm_l2_station_entry_t), 2001 "Sw L2 station entry"); 2002 if (NULL == s_ent_p) { 2003 rv = BCM_E_MEMORY; 2004 goto cleanup; 2005 } 2006 2007 sal_memset(s_ent_p, 0, sizeof(_bcm_l2_station_entry_t)); 2008 2009 s_ent_p->sid = ++sc->last_allocated_sid; 2010 s_ent_p->prio = (sc->entries_total - index); 2011 sc->entries_free--; 2012 sc->entry_count++; 2013 sc->entry_arr[index] = s_ent_p; 2014 2015 s_ent_p->hw_index = index; 2016 s_ent_p->flags |= _BCM_L2_STATION_ENTRY_INSTALLED; 2017 } 2018 2019 cleanup: 2020 2021 SC_UNLOCK(sc); 2022 2023 if (tcam_buf) { 2024 soc_cm_sfree(unit, tcam_buf); 2025 } 2026 2027 return (rv); 2028 } 2029 2030 /* 2031 * Function: 2032 * _bcm_th3_l2_station_reload 2033 * Purpose: 2034 * Re-construct L2 station control structure software state 2035 * from installed hardware entries 2036 * Parameters: 2037 * unit - (IN) BCM device number 2038 * Returns: 2039 * BCM_E_XXX 2040 */ 2041 int 2042 _bcm_th3_l2_station_reload(int unit) 2043 { 2044 int rv; 2045 2046 rv = _bcm_th3_l2_station_entry_reload(unit, _BCM_L2_STATION_ENTRY_UNDERLAY); 2047 2048 return rv; 2049 } 2050 2051 2052 #endif /* BCM_TRIUMPH_SUPPORT */ 2053 #endif /* BCM_WARM_BOOT_SUPPORT */ 2054 #endif /* BCM_TOMAHAWK3_SUPPORT */