l2xmsg.c (113584B)
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: l2xmsg.c 8 * Purpose: Provide a reliable stream of L2 insert/delete messages. 9 * 10 * This module monitors the L2X table for changes and performs callbacks 11 * for each insert, delete, or port movement that is detected. 12 * 13 * There is a time lag from the actual table change to the callback 14 * because the l2xmsg task scans the L2X table only periodically. 15 */ 16 17 #include <sal/core/libc.h> 18 #include <shared/alloc.h> 19 #include <sal/core/spl.h> 20 #include <sal/core/time.h> 21 #include <shared/bsl.h> 22 #include <soc/mem.h> 23 #include <soc/debug.h> 24 #include <soc/cm.h> 25 #include <soc/drv.h> 26 #include <soc/l2x.h> 27 #include <soc/ism_hash.h> 28 #include <soc/triumph3.h> 29 30 #ifdef BCM_TRIUMPH3_SUPPORT 31 32 #define L2X_ENTRY_EQL(unit, e1, e2, hit) \ 33 (!_soc_mem_cmp_tr3_l2x_sync(unit, (void *) e1, (void *) e2, hit)) 34 #define EXT_L2X_1_ENTRY_EQL(unit, e1, e2, hit) \ 35 (!_soc_mem_cmp_tr3_ext_l2x_1_sync(unit, (void *) e1, (void *) e2, hit)) 36 #define EXT_L2X_2_ENTRY_EQL(unit, e1, e2, hit) \ 37 (!_soc_mem_cmp_tr3_ext_l2x_2_sync(unit, (void *) e1, (void *) e2, hit)) 38 39 #define L2X_IS_VALID_ENTRY(_u, _mem, _e, bitf) \ 40 soc_mem_field32_get((_u), (_mem), (_e), bitf) 41 42 43 STATIC void _soc_tr3_l2x_thread(void *unit_vp); 44 45 #define SOC_MEM_L2_INT_LOCK(unit) \ 46 soc_mem_lock(unit, L2_ENTRY_1m); \ 47 soc_mem_lock(unit, L2_ENTRY_2m); 48 49 #define SOC_MEM_L2_INT_UNLOCK(unit) \ 50 soc_mem_unlock(unit, L2_ENTRY_2m); \ 51 soc_mem_unlock(unit, L2_ENTRY_1m); 52 53 #define SOC_MEM_L2_EXT_1_LOCK(unit) \ 54 soc_mem_lock(unit, EXT_L2_ENTRY_1m); 55 56 #define SOC_MEM_L2_EXT_1_UNLOCK(unit) \ 57 soc_mem_unlock(unit, EXT_L2_ENTRY_1m); 58 59 #define SOC_MEM_L2_EXT_2_LOCK(unit) \ 60 soc_mem_lock(unit, EXT_L2_ENTRY_2m); 61 62 #define SOC_MEM_L2_EXT_2_UNLOCK(unit) \ 63 soc_mem_unlock(unit, EXT_L2_ENTRY_2m); 64 65 #define SOC_TR3_L2X_BUCKET_SIZE 4 66 67 /**************************************************************************** 68 * 69 * L2X Message Registration 70 */ 71 72 #define L2X_CB_MAX 3 73 74 typedef struct l2x_cb_entry_s { 75 soc_l2_entry_cb_fn fn; 76 void *fn_data; 77 } l2_entry_cb_entry_t; 78 79 typedef struct l2x_data_s { 80 uint8 enabled; /* Set to true if a L2 data store is being used, 81 applicable for POLL mode */ 82 uint8 int_avail; 83 uint8 ext1_avail; 84 uint8 ext2_avail; 85 l2_entry_cb_entry_t cb[L2X_CB_MAX]; 86 int cb_count; 87 /* Internal ISM based memory: We manage type 1 and 2 using a single set */ 88 int entry_bytes_int; 89 int entry_words_int; 90 uint32 *shadow_tab_int; 91 SHR_BITDCL *del_map_int; 92 SHR_BITDCL *cb_map_int; 93 /* External ESM based memories: Two sets for type 1 and type 2 respectively */ 94 int entry_bytes_ext1; 95 int entry_words_ext1; 96 uint32 *shadow_tab_ext1; 97 SHR_BITDCL *del_map_ext1; 98 SHR_BITDCL *cb_map_ext1; 99 int entry_bytes_ext2; 100 int entry_words_ext2; 101 uint32 *shadow_tab_ext2; 102 SHR_BITDCL *del_map_ext2; 103 SHR_BITDCL *cb_map_ext2; 104 } l2_entry_data_t; 105 106 static l2_entry_data_t tr3_l2x_data[SOC_MAX_NUM_DEVICES]; 107 108 #define L2X_ENTRY_CALLBACK_SET(_u_, _index_) \ 109 { \ 110 SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_int, (_index_)); \ 111 LOG_INFO(BSL_LS_SOC_ARL, \ 112 (BSL_META_U(unit, \ 113 "set_entry_callback: u:%d i=%d\n"), \ 114 _u_, _index_)); \ 115 } 116 117 #define L2X_ENTRY_DELETED_SET(_u_, _index_) \ 118 { \ 119 SHR_BITSET(tr3_l2x_data[(_u_)].del_map_int, (_index_)); \ 120 LOG_VERBOSE(BSL_LS_SOC_ARL, \ 121 (BSL_META_U(unit, \ 122 "set_entry_deleted: u:%d i=%d\n"), \ 123 _u_, _index_)); \ 124 } 125 126 #define EXT_L2X_1_ENTRY_CALLBACK_SET(_u_, _index_) \ 127 { \ 128 SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_ext1, (_index_)); \ 129 LOG_INFO(BSL_LS_SOC_ARL, \ 130 (BSL_META_U(unit, \ 131 "set_entry_callback: u:%d i=%d\n"), \ 132 _u_, _index_)); \ 133 } 134 135 #define EXT_L2X_1_ENTRY_DELETED_SET(_u_, _index_) \ 136 { \ 137 SHR_BITSET(tr3_l2x_data[(_u_)].del_map_ext1, (_index_)); \ 138 LOG_VERBOSE(BSL_LS_SOC_ARL, \ 139 (BSL_META_U(unit, \ 140 "set_entry_deleted: u:%d i=%d\n"), \ 141 _u_, _index_)); \ 142 } 143 144 #define EXT_L2X_2_ENTRY_CALLBACK_SET(_u_, _index_) \ 145 { \ 146 SHR_BITSET(tr3_l2x_data[(_u_)].cb_map_ext2, (_index_)); \ 147 LOG_INFO(BSL_LS_SOC_ARL, \ 148 (BSL_META_U(unit, \ 149 "set_entry_callback: u:%d i=%d\n"), \ 150 _u_, _index_)); \ 151 } 152 153 #define EXT_L2X_2_ENTRY_DELETED_SET(_u_, _index_) \ 154 { \ 155 SHR_BITSET(tr3_l2x_data[(_u_)].del_map_ext2, (_index_)); \ 156 LOG_VERBOSE(BSL_LS_SOC_ARL, \ 157 (BSL_META_U(unit, \ 158 "set_entry_deleted: u:%d i=%d\n"), \ 159 _u_, _index_)); \ 160 } 161 162 #define L2X_IS_CPU_DELETED(_u_, _index_) \ 163 SHR_BITGET(tr3_l2x_data[(_u_)].del_map_int, (_index_)) 164 165 #define SOC_L2X_TGID_TRUNK_INDICATOR(unit) \ 166 SOC_IS_RAVEN(unit) ? 0x40 : 0x20 167 #define SOC_L2X_TGID_PORT_TRUNK_MASK 0x1f 168 #define SOC_L2X_TGID_PORT_TRUNK_MASK_HI 0x60 169 170 /* 171 * Function: 172 * soc_l2_entry_register 173 * Purpose: 174 * Register a callback routine to be notified of all inserts, 175 * deletes, and updates to the L2X table. 176 * Parameters: 177 * unit - StrataSwitch unit number 178 * fn - Callback function to register 179 * fn_data - Extra data passed to callback function 180 * Returns: 181 * SOC_E_NONE - Success 182 * SOC_E_MEMORY - Too many callbacks registered 183 */ 184 185 int 186 soc_l2_entry_register(int unit, soc_l2_entry_cb_fn fn, void *fn_data) 187 { 188 l2_entry_data_t *ad = &tr3_l2x_data[unit]; 189 int i; 190 #ifdef BCM_XGS3_SWITCH_SUPPORT 191 soc_control_t *soc = SOC_CONTROL(unit); 192 int mode; 193 194 mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL); 195 196 if ((mode == L2MODE_FIFO) && !soc_feature(unit, soc_feature_l2_modfifo)) { 197 mode = L2MODE_POLL; 198 } 199 200 if ((mode == L2MODE_POLL) && soc->l2x_external) { 201 /* Not supported for external L2 memory configuration. */ 202 return SOC_E_UNAVAIL; 203 } 204 #endif 205 206 if (!soc_feature(unit, soc_feature_arl_hashed)) { 207 return SOC_E_UNAVAIL; 208 } 209 210 if (ad->cb_count >= L2X_CB_MAX) { 211 return SOC_E_MEMORY; 212 } 213 214 for (i = 0; i < ad->cb_count; i++) { 215 if ((ad->cb[i].fn == fn && 216 ad->cb[i].fn_data == fn_data)) { 217 return SOC_E_NONE; /* Already registered */ 218 } 219 } 220 221 ad->cb[ad->cb_count].fn = fn; 222 ad->cb[ad->cb_count].fn_data = fn_data; 223 224 ad->cb_count++; 225 226 return SOC_E_NONE; 227 } 228 229 /* 230 * Function: 231 * soc_l2_entry_unregister 232 * Purpose: 233 * Unregister a callback routine; requires same args as when registered 234 * Parameters: 235 * unit - StrataSwitch unit number 236 * fn - Callback function to unregister; NULL to unregister all 237 * fn_data - Extra data passed to callback function; 238 * must match registered value unless fn is NULL 239 * Returns: 240 * SOC_E_NONE - Success 241 * SOC_E_NOT_FOUND - Matching registered routine not found 242 */ 243 244 int 245 soc_l2_entry_unregister(int unit, soc_l2_entry_cb_fn fn, void *fn_data) 246 { 247 l2_entry_data_t *ad = &tr3_l2x_data[unit]; 248 int i; 249 250 if (fn == NULL) { 251 ad->cb_count = 0; 252 return SOC_E_NONE; 253 } 254 255 for (i = 0; i < ad->cb_count; i++) { 256 if ((ad->cb[i].fn == fn && 257 ad->cb[i].fn_data == fn_data)) { 258 259 for (ad->cb_count--; i < ad->cb_count; i++) { 260 sal_memcpy(&ad->cb[i], &ad->cb[i + 1], 261 sizeof (l2_entry_cb_entry_t)); 262 } 263 264 return SOC_E_NONE; 265 } 266 } 267 268 return SOC_E_NOT_FOUND; 269 } 270 271 /* 272 * Function: 273 * soc_l2_entry_callback 274 * Purpose: 275 * Routine to execute all callbacks on the list. 276 * Parameters: 277 * unit - unit number. 278 * entry_del - deleted or updated entry, NULL if none. 279 * entry_add - added or updated entry, NULL if none. 280 */ 281 282 void 283 soc_l2_entry_callback(int unit, uint32 flags, soc_mem_t mem_type, 284 l2_combo_entry_t *entry_del, l2_combo_entry_t *entry_add) 285 { 286 l2_entry_data_t *ad = &tr3_l2x_data[unit]; 287 int i; 288 289 LOG_VERBOSE(BSL_LS_SOC_COMMON, 290 (BSL_META_U(unit, 291 "%s %s %s\n"), FUNCTION_NAME(), entry_del ? "DEL" : "", 292 entry_add ? "ADD" : "")); 293 for (i = 0; i < ad->cb_count; i++) { 294 (*ad->cb[i].fn)(unit, flags, mem_type, entry_del, entry_add, ad->cb[i].fn_data); 295 } 296 } 297 298 /* 299 * Function: 300 * soc_l2x_running 301 * Purpose: 302 * Determine the L2X sync thread running parameters 303 * Parameters: 304 * unit - unit number. 305 * flags (OUT) - if non-NULL, receives the current flag settings 306 * interval (OUT) - if non-NULL, receives the current pass interval 307 * Returns: 308 * Boolean; TRUE if L2X sync thread is running 309 */ 310 311 int 312 soc_tr3_l2x_running(int unit, uint32 *flags, sal_usecs_t *interval) 313 { 314 soc_control_t *soc = SOC_CONTROL(unit); 315 316 if (soc->l2x_pid != SAL_THREAD_ERROR) { 317 if (flags != NULL) { 318 *flags = soc->l2x_flags; 319 } 320 if (interval != NULL) { 321 *interval = soc->l2x_interval; 322 } 323 } 324 325 return(soc->l2x_pid != SAL_THREAD_ERROR); 326 } 327 328 /* It can only handle delete so far */ 329 int 330 _soc_tr3_l2x_sync_replace(int unit, _soc_tr3_l2_replace_t *rep_st, 331 uint32 flags) 332 { 333 soc_control_t *soc = SOC_CONTROL(unit); 334 uint32 kt, *entry, *match_data, *match_mask; 335 int index_max, entry_words, idx, i; 336 soc_memacc_t l21_key_type; 337 soc_mem_t mem_type; 338 339 if (soc->l2x_pid == SAL_THREAD_ERROR) { 340 /* thread not running */ 341 return SOC_E_NONE; 342 } 343 344 /* First work on Internal L2 */ 345 entry = tr3_l2x_data[unit].shadow_tab_int; 346 if (entry == NULL) { 347 return SOC_E_NONE; 348 } 349 350 SOC_IF_ERROR_RETURN 351 (soc_memacc_init(unit, L2_ENTRY_1m, KEY_TYPEf, &l21_key_type)); 352 353 index_max = soc_mem_index_max(unit, L2_ENTRY_1m); 354 (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER); 355 for (idx = 0; idx <= index_max; ) { 356 mem_type = L2_ENTRY_1m; 357 match_data = (uint32 *)&rep_st->match_data1; 358 match_mask = (uint32 *)&rep_st->match_mask1; 359 kt = soc_memacc_field32_get(&l21_key_type, entry); 360 if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 361 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 362 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 363 mem_type = L2_ENTRY_2m; 364 match_data = (uint32 *)&rep_st->match_data2; 365 match_mask = (uint32 *)&rep_st->match_mask2; 366 } 367 entry_words = soc_mem_entry_words(unit, mem_type); 368 for (i = 0; i < entry_words; i++) { 369 if ((entry[i] ^ match_data[i]) & match_mask[i]) { 370 break; 371 } 372 } 373 if (i != entry_words) { 374 entry += entry_words; 375 if (mem_type == L2_ENTRY_1m) { 376 idx++; 377 } else { 378 idx += 2; 379 } 380 continue; 381 } 382 soc_tr3_l2x_sync_delete(unit, mem_type, entry, idx, flags); 383 if (mem_type == L2_ENTRY_1m) { 384 idx++; 385 } else { 386 idx += 2; 387 } 388 entry += entry_words; 389 } 390 (void)sal_sem_give(soc->l2x_lock); 391 392 /* Then work on external L2 */ 393 if (!soc_feature(unit, soc_feature_esm_support)) { 394 return SOC_E_NONE; 395 } 396 /* First work on EXT_L2_ENTRY_1 */ 397 entry = tr3_l2x_data[unit].shadow_tab_ext1; 398 if (entry == NULL) { 399 return SOC_E_NONE; 400 } 401 index_max = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 402 entry_words = soc_mem_entry_words(unit, EXT_L2_ENTRY_1m); 403 (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER); 404 for (idx = 0; idx <= index_max; idx++, entry += entry_words) { 405 match_data = (uint32 *)&rep_st->ext_match_data1; 406 match_mask = (uint32 *)&rep_st->ext_match_mask1; 407 for (i = 0; i < entry_words; i++) { 408 if ((entry[i] ^ match_data[i]) & match_mask[i]) { 409 break; 410 } 411 } 412 if (i != entry_words) { 413 continue; 414 } 415 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, idx, flags); 416 } 417 (void)sal_sem_give(soc->l2x_lock); 418 419 /* Then work on EXT_L2_ENTRY_2 */ 420 entry = tr3_l2x_data[unit].shadow_tab_ext2; 421 if (entry == NULL) { 422 return SOC_E_NONE; 423 } 424 index_max = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 425 entry_words = soc_mem_entry_words(unit, EXT_L2_ENTRY_2m); 426 (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER); 427 for (idx = 0; idx <= index_max; idx++, entry += entry_words) { 428 match_data = (uint32 *)&rep_st->ext_match_data2; 429 match_mask = (uint32 *)&rep_st->ext_match_mask2; 430 for (i = 0; i < entry_words; i++) { 431 if ((entry[i] ^ match_data[i]) & match_mask[i]) { 432 break; 433 } 434 } 435 if (i != entry_words) { 436 continue; 437 } 438 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, idx, flags); 439 } 440 (void)sal_sem_give(soc->l2x_lock); 441 442 return SOC_E_NONE; 443 } 444 445 /* 446 * Function: 447 * _soc_tr3_l2x_sync_delete_by 448 * Purpose: 449 * Search all the entries in the shadow table based on the 450 * criteria and mark them as deleted. 451 * Parameters: 452 * Returns: 453 * SOC_E_XX 454 */ 455 int 456 _soc_tr3_l2x_sync_delete_by(int unit, uint32 mod, uint32 port, 457 uint16 vid, uint32 tid, int vfi, 458 uint32 flags, uint32 search_key) 459 { 460 soc_control_t *soc = SOC_CONTROL(unit); 461 int rv = SOC_E_NONE, static_bit_val; 462 int index, max_index, stl2; 463 uint32 *entry = NULL; 464 uint32 port_val, mod_id; 465 vlan_id_t vlan_id; 466 467 468 if (soc->l2x_pid == SAL_THREAD_ERROR) { 469 /* thread not running */ 470 return SOC_E_NONE; 471 } 472 stl2 = (flags & SOC_L2X_INC_STATIC) ? 1 : 0; 473 (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER); 474 entry = tr3_l2x_data[unit].shadow_tab_int; 475 if (!entry) { 476 goto exit; 477 } 478 479 max_index = soc_mem_index_max(unit, L2_ENTRY_1m); 480 481 if (search_key == SOC_L2X_PORTMOD_DEL) { 482 /* First work through L2_ENTRY_1 */ 483 for (index = 0; index < max_index; index++, 484 entry += tr3_l2x_data[unit].entry_words_int) { 485 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 486 entry, VALIDf)) { 487 continue; 488 } 489 if (soc_mem_field32_get(unit, L2_ENTRY_1m, entry, 490 L2__DEST_TYPEf) == 1) { 491 continue; 492 } 493 port_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 494 entry, L2__PORT_NUMf); 495 mod_id = soc_mem_field32_get(unit, L2_ENTRY_1m, 496 entry, L2__MODULE_IDf); 497 if ((port != port_val) || (mod != mod_id)) { 498 continue; 499 } 500 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 501 entry, STATIC_BITf); 502 if (stl2 || (stl2 == static_bit_val)) { 503 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags); 504 } 505 } 506 507 /* Then work through L2_ENTRY_2 */ 508 entry = tr3_l2x_data[unit].shadow_tab_int; 509 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 510 for (index = 0; index < max_index; index+=2, 511 entry += tr3_l2x_data[unit].entry_words_int * 2) { 512 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 513 entry, VALID_0f)) { 514 continue; 515 } 516 if (soc_mem_field32_get(unit, L2_ENTRY_2m, entry, 517 L2__DEST_TYPEf) == 1) { 518 continue; 519 } 520 port_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 521 entry, L2__PORT_NUMf); 522 mod_id = soc_mem_field32_get(unit, L2_ENTRY_2m, 523 entry, L2__MODULE_IDf); 524 if ((port != port_val) || (mod != mod_id)) { 525 continue; 526 } 527 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 528 entry, STATIC_BITf); 529 if (stl2 || (stl2 == static_bit_val)) { 530 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags); 531 } 532 } 533 534 if (soc_feature(unit, soc_feature_esm_support)) { 535 /* First work through EXT_L2_ENTRY_1 */ 536 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 537 entry = tr3_l2x_data[unit].shadow_tab_ext1; 538 if (entry) { 539 for (index = 0; index < max_index; index++, 540 entry += tr3_l2x_data[unit].entry_words_ext1) { 541 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 542 entry, FREEf)) { 543 continue; 544 } 545 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, entry, 546 DEST_TYPEf) == 1) { 547 continue; 548 } 549 port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 550 entry, PORT_NUMf); 551 mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 552 entry, MODULE_IDf); 553 if ((port != port_val) || (mod != mod_id)) { 554 continue; 555 } 556 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 557 entry, STATIC_BITf); 558 if (stl2 || (stl2 == static_bit_val)) { 559 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 560 index, flags); 561 } 562 } 563 } 564 565 /* Then work through EXT_L2_ENTRY_2 */ 566 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 567 entry = tr3_l2x_data[unit].shadow_tab_ext2; 568 if (entry) { 569 for (index = 0; index < max_index; index++, 570 entry += tr3_l2x_data[unit].entry_words_ext2) { 571 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 572 entry, FREEf)) { 573 continue; 574 } 575 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, entry, 576 DEST_TYPEf) == 1) { 577 continue; 578 } 579 port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 580 entry, PORT_NUMf); 581 mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 582 entry, MODULE_IDf); 583 if ((port != port_val) || (mod != mod_id)) { 584 continue; 585 } 586 587 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 588 entry, STATIC_BITf); 589 if (stl2 || (stl2 == static_bit_val)) { 590 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 591 index, flags); 592 } 593 } 594 } 595 } 596 goto exit; 597 } 598 599 if (search_key == SOC_L2X_VLAN_DEL) { 600 /* First work through L2_ENTRY_1 */ 601 for (index = 0; index < max_index; index++, 602 entry += tr3_l2x_data[unit].entry_words_int) { 603 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 604 entry, VALIDf)) { 605 continue; 606 } 607 vlan_id = soc_mem_field32_get(unit, L2_ENTRY_1m, 608 entry, L2__VLAN_IDf); 609 if (vid != vlan_id) { 610 continue; 611 } 612 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 613 entry, STATIC_BITf); 614 if (stl2 || (stl2 == static_bit_val)) { 615 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags); 616 } 617 } 618 619 /* Then work through L2_ENTRY_2 */ 620 entry = tr3_l2x_data[unit].shadow_tab_int; 621 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 622 for (index = 0; index < max_index; index+=2, 623 entry += tr3_l2x_data[unit].entry_words_int * 2) { 624 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 625 entry, VALID_0f)) { 626 continue; 627 } 628 vlan_id = soc_mem_field32_get(unit, L2_ENTRY_2m, 629 entry, L2__VLAN_IDf); 630 if (vid != vlan_id) { 631 continue; 632 } 633 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 634 entry, STATIC_BITf); 635 if (stl2 || (stl2 == static_bit_val)) { 636 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags); 637 } 638 } 639 640 if (soc_feature(unit, soc_feature_esm_support)) { 641 /* First work through EXT_L2_ENTRY_1 */ 642 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 643 entry = tr3_l2x_data[unit].shadow_tab_ext1; 644 if (entry) { 645 for (index = 0; index < max_index; index++, 646 entry += tr3_l2x_data[unit].entry_words_ext1) { 647 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 648 entry, FREEf)) { 649 continue; 650 } 651 vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 652 entry, VLAN_IDf); 653 if (vid != vlan_id) { 654 continue; 655 } 656 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 657 entry, STATIC_BITf); 658 if (stl2 || (stl2 == static_bit_val)) { 659 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 660 index, flags); 661 } 662 } 663 } 664 665 /* Then work through EXT_L2_ENTRY_2 */ 666 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 667 entry = tr3_l2x_data[unit].shadow_tab_ext2; 668 if (entry) { 669 for (index = 0; index < max_index; index++, 670 entry += tr3_l2x_data[unit].entry_words_ext2) { 671 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 672 entry, FREEf)) { 673 continue; 674 } 675 vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 676 entry, VLAN_IDf); 677 if (vid != vlan_id) { 678 continue; 679 } 680 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 681 entry, STATIC_BITf); 682 if (stl2 || (stl2 == static_bit_val)) { 683 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 684 index, flags); 685 } 686 } 687 } 688 } 689 goto exit; 690 } 691 692 if (search_key == SOC_L2X_VFI_DEL) { 693 int vfi_id; 694 /* First work through L2_ENTRY_1 */ 695 for (index = 0; index < max_index; index++, 696 entry += tr3_l2x_data[unit].entry_words_int) { 697 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 698 entry, VALIDf)) { 699 continue; 700 } 701 vfi_id = soc_mem_field32_get(unit, L2_ENTRY_1m, 702 entry, L2__VFIf); 703 if (vfi != vfi_id) { 704 continue; 705 } 706 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 707 entry, STATIC_BITf); 708 if (stl2 || (stl2 == static_bit_val)) { 709 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags); 710 } 711 } 712 713 /* Then work through L2_ENTRY_2 */ 714 entry = tr3_l2x_data[unit].shadow_tab_int; 715 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 716 for (index = 0; index < max_index; index+=2, 717 entry += tr3_l2x_data[unit].entry_words_int * 2) { 718 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 719 entry, VALID_0f)) { 720 continue; 721 } 722 vfi_id = soc_mem_field32_get(unit, L2_ENTRY_2m, 723 entry, L2__VFIf); 724 if (vfi != vfi_id) { 725 continue; 726 } 727 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 728 entry, STATIC_BITf); 729 if (stl2 || (stl2 == static_bit_val)) { 730 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags); 731 } 732 } 733 734 if (soc_feature(unit, soc_feature_esm_support)) { 735 /* First work through EXT_L2_ENTRY_1 */ 736 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 737 entry = tr3_l2x_data[unit].shadow_tab_ext1; 738 if (entry) { 739 for (index = 0; index < max_index; index++, 740 entry += tr3_l2x_data[unit].entry_words_ext1) { 741 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 742 entry, FREEf)) { 743 continue; 744 } 745 vfi_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 746 entry, VFIf); 747 if (vfi != vfi_id) { 748 continue; 749 } 750 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 751 entry, STATIC_BITf); 752 if (stl2 || (stl2 == static_bit_val)) { 753 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 754 index, flags); 755 } 756 } 757 } 758 759 /* Then work through EXT_L2_ENTRY_2 */ 760 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 761 entry = tr3_l2x_data[unit].shadow_tab_ext2; 762 if (entry) { 763 for (index = 0; index < max_index; index++, 764 entry += tr3_l2x_data[unit].entry_words_ext2) { 765 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 766 entry, FREEf)) { 767 continue; 768 } 769 vfi_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 770 entry, VFIf); 771 if (vfi != vfi_id) { 772 continue; 773 } 774 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 775 entry, STATIC_BITf); 776 if (stl2 || (stl2 == static_bit_val)) { 777 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 778 index, flags); 779 } 780 } 781 } 782 } 783 goto exit; 784 } 785 786 if (search_key == SOC_L2X_PORTMOD_VLAN_DEL) { 787 /* First work through L2_ENTRY_1 */ 788 for (index = 0; index < max_index; index++, 789 entry += tr3_l2x_data[unit].entry_words_int) { 790 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 791 entry, VALIDf)) { 792 continue; 793 } 794 if (soc_mem_field32_get(unit, L2_ENTRY_1m, entry, 795 L2__DEST_TYPEf) == 1) { 796 continue; 797 } 798 port_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 799 entry, L2__PORT_NUMf); 800 mod_id = soc_mem_field32_get(unit, L2_ENTRY_1m, 801 entry, L2__MODULE_IDf); 802 vlan_id = soc_mem_field32_get(unit, L2_ENTRY_1m, 803 entry, L2__VLAN_IDf); 804 if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) { 805 continue; 806 } 807 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 808 entry, STATIC_BITf); 809 if (stl2 || (stl2 == static_bit_val)) { 810 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags); 811 } 812 } 813 814 /* Then work through L2_ENTRY_2 */ 815 entry = tr3_l2x_data[unit].shadow_tab_int; 816 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 817 for (index = 0; index < max_index; index+=2, 818 entry += tr3_l2x_data[unit].entry_words_int * 2) { 819 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 820 entry, VALID_0f)) { 821 continue; 822 } 823 if (soc_mem_field32_get(unit, L2_ENTRY_2m, entry, 824 L2__DEST_TYPEf) == 1) { 825 continue; 826 } 827 port_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 828 entry, L2__PORT_NUMf); 829 mod_id = soc_mem_field32_get(unit, L2_ENTRY_2m, 830 entry, L2__MODULE_IDf); 831 vlan_id = soc_mem_field32_get(unit, L2_ENTRY_2m, 832 entry, L2__VLAN_IDf); 833 if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) { 834 continue; 835 } 836 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 837 entry, STATIC_BITf); 838 if (stl2 || (stl2 == static_bit_val)) { 839 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags); 840 } 841 } 842 843 if (soc_feature(unit, soc_feature_esm_support)) { 844 /* First work through EXT_L2_ENTRY_1 */ 845 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 846 entry = tr3_l2x_data[unit].shadow_tab_ext1; 847 if (entry) { 848 for (index = 0; index < max_index; index++, 849 entry += tr3_l2x_data[unit].entry_words_ext1) { 850 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 851 entry, FREEf)) { 852 continue; 853 } 854 port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 855 entry, PORT_NUMf); 856 mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 857 entry, MODULE_IDf); 858 vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 859 entry, VLAN_IDf); 860 if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) { 861 continue; 862 } 863 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 864 entry, STATIC_BITf); 865 if (stl2 || (stl2 == static_bit_val)) { 866 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 867 index, flags); 868 } 869 } 870 } 871 872 /* Then work through EXT_L2_ENTRY_2 */ 873 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 874 entry = tr3_l2x_data[unit].shadow_tab_ext2; 875 if (entry) { 876 for (index = 0; index < max_index; index++, 877 entry += tr3_l2x_data[unit].entry_words_ext2) { 878 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 879 entry, FREEf)) { 880 continue; 881 } 882 port_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 883 entry, PORT_NUMf); 884 mod_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 885 entry, MODULE_IDf); 886 vlan_id = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 887 entry, VLAN_IDf); 888 if ((vid != vlan_id) ||(port != port_val) ||(mod != mod_id)) { 889 continue; 890 } 891 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 892 entry, STATIC_BITf); 893 if (stl2 || (stl2 == static_bit_val)) { 894 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 895 index, flags); 896 } 897 } 898 } 899 } 900 goto exit; 901 } 902 903 if ((search_key == SOC_L2X_TRUNK_DEL) || 904 (search_key == SOC_L2X_TRUNK_VLAN_DEL)) { 905 /* First work through L2_ENTRY_1 */ 906 for (index = 0; index < max_index; index++, 907 entry += tr3_l2x_data[unit].entry_words_int) { 908 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_1m, 909 entry, VALIDf)) { 910 continue; 911 } 912 if ((soc_mem_field32_get(unit, L2_ENTRY_1m, 913 entry, L2__DEST_TYPEf) != 1) || 914 (soc_mem_field32_get(unit, L2_ENTRY_1m, 915 entry, L2__TGIDf) != tid)) { 916 continue; 917 } 918 if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 919 (vid != soc_mem_field32_get(unit, L2_ENTRY_1m, 920 entry, L2__VLAN_IDf))) { 921 continue; 922 } 923 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_1m, 924 entry, STATIC_BITf); 925 if (stl2 || (stl2 == static_bit_val)) { 926 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_1m, entry, index, flags); 927 } 928 } 929 930 /* Then work through L2_ENTRY_2 */ 931 entry = tr3_l2x_data[unit].shadow_tab_int; 932 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 933 for (index = 0; index < max_index; index+=2, 934 entry += tr3_l2x_data[unit].entry_words_int * 2) { 935 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 936 entry, VALID_0f)) { 937 continue; 938 } 939 if ((soc_mem_field32_get(unit, L2_ENTRY_2m, 940 entry, L2__DEST_TYPEf) != 1) || 941 (soc_mem_field32_get(unit, L2_ENTRY_2m, 942 entry, L2__TGIDf) != tid)) { 943 continue; 944 } 945 if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 946 (vid != soc_mem_field32_get(unit, L2_ENTRY_2m, 947 entry, L2__VLAN_IDf))) { 948 continue; 949 } 950 static_bit_val = soc_mem_field32_get(unit, L2_ENTRY_2m, 951 entry, STATIC_BITf); 952 if (stl2 || (stl2 == static_bit_val)) { 953 soc_tr3_l2x_sync_delete(unit, L2_ENTRY_2m, entry, index, flags); 954 } 955 } 956 957 if (soc_feature(unit, soc_feature_esm_support)) { 958 /* First work through EXT_L2_ENTRY_1 */ 959 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_1m); 960 entry = tr3_l2x_data[unit].shadow_tab_ext1; 961 if (entry) { 962 for (index = 0; index < max_index; index++, 963 entry += tr3_l2x_data[unit].entry_words_ext1) { 964 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_1m, 965 entry, FREEf)) { 966 continue; 967 } 968 if ((soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 969 entry, DEST_TYPEf) != 1) || 970 (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 971 entry, TGIDf) != tid)) { 972 continue; 973 } 974 if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 975 (vid != soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 976 entry, VLAN_IDf))) { 977 continue; 978 } 979 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, 980 entry, STATIC_BITf); 981 if (stl2 || (stl2 == static_bit_val)) { 982 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_1m, entry, 983 index, flags); 984 } 985 } 986 } 987 988 /* Then work through EXT_L2_ENTRY_2 */ 989 max_index = soc_mem_index_max(unit, EXT_L2_ENTRY_2m); 990 entry = tr3_l2x_data[unit].shadow_tab_ext2; 991 if (entry) { 992 for (index = 0; index < max_index; index++, 993 entry += tr3_l2x_data[unit].entry_words_ext2) { 994 if (L2X_IS_VALID_ENTRY(unit, EXT_L2_ENTRY_2m, 995 entry, FREEf)) { 996 continue; 997 } 998 if ((soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 999 entry, DEST_TYPEf) != 1) || 1000 (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 1001 entry, TGIDf) != tid)) { 1002 continue; 1003 } 1004 if ((search_key == SOC_L2X_TRUNK_VLAN_DEL) && 1005 (vid != soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 1006 entry, VLAN_IDf))) { 1007 continue; 1008 } 1009 static_bit_val = soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, 1010 entry, STATIC_BITf); 1011 if (stl2 || (stl2 == static_bit_val)) { 1012 soc_tr3_l2x_sync_delete(unit, EXT_L2_ENTRY_2m, entry, 1013 index, flags); 1014 } 1015 } 1016 } 1017 } 1018 goto exit; 1019 } 1020 1021 rv = SOC_E_PARAM; 1022 1023 exit: 1024 (void)sal_sem_give(soc->l2x_lock); 1025 return rv; 1026 } 1027 1028 /* 1029 * Function: 1030 * soc_tr3_l2x_sync_delete 1031 * Purpose: 1032 * sync the SW shadow copy for the deleted entry from HW. 1033 * Parameters: 1034 * unit - unit number. 1035 * del_entry - entry deleted from the HW l2X memory 1036 * Returns: 1037 * SOC_E_XX 1038 */ 1039 1040 int 1041 soc_tr3_l2x_sync_delete(int unit, soc_mem_t mem, uint32 *del_entry, int index, 1042 uint32 flags) 1043 { 1044 soc_control_t *soc = SOC_CONTROL(unit); 1045 int max_index; 1046 uint32 *tab_p, kt; 1047 soc_mem_t mem_type; 1048 1049 LOG_INFO(BSL_LS_SOC_ARL, 1050 (BSL_META_U(unit, 1051 "soc_tr3_l2x_sync_delete: unit=%d index=%d\n"), 1052 unit, index)); 1053 1054 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1055 /* thread not running */ 1056 return SOC_E_NONE; 1057 } 1058 1059 if (!tr3_l2x_data[unit].enabled) { 1060 return SOC_E_NONE; 1061 } 1062 1063 if (mem == L2_ENTRY_1m || mem == L2_ENTRY_2m) { 1064 /* Determine entry type/size */ 1065 mem_type = L2_ENTRY_1m; 1066 kt = soc_mem_field32_get(unit, L2_ENTRY_1m, del_entry, KEY_TYPEf); 1067 if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1068 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1069 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1070 mem_type = L2_ENTRY_2m; 1071 } 1072 if (mem_type == L2_ENTRY_1m) { 1073 max_index = soc_mem_index_max(unit, L2_ENTRY_1m); 1074 } else { 1075 max_index = soc_mem_index_max(unit, L2_ENTRY_2m); 1076 } 1077 if (index > max_index) { 1078 return SOC_E_PARAM; 1079 } 1080 1081 /* 1082 * validate that the entry in the shadow copy is same as the entry 1083 * deleted. 1084 */ 1085 if (mem_type == L2_ENTRY_1m) { 1086 tab_p = tr3_l2x_data[unit].shadow_tab_int + 1087 (index * tr3_l2x_data[unit].entry_words_int); 1088 } else { 1089 tab_p = tr3_l2x_data[unit].shadow_tab_int + 1090 (index * tr3_l2x_data[unit].entry_words_int * 2); 1091 } 1092 if (L2X_ENTRY_EQL(unit, del_entry, tab_p, 0)) { 1093 L2X_ENTRY_DELETED_SET(unit, index); 1094 /* Bitmap that indicates to suppress callback */ 1095 if ((flags & SOC_L2X_NO_CALLBACKS)) { 1096 L2X_ENTRY_CALLBACK_SET(unit, index); 1097 } 1098 } 1099 } else if (mem == EXT_L2_ENTRY_1m) { 1100 if (index > soc_mem_index_max(unit, EXT_L2_ENTRY_1m)) { 1101 return SOC_E_PARAM; 1102 } 1103 /* 1104 * validate that the entry in the shadow copy is same as the entry 1105 * deleted. 1106 */ 1107 tab_p = tr3_l2x_data[unit].shadow_tab_ext1 + 1108 (index * tr3_l2x_data[unit].entry_words_ext1); 1109 if (EXT_L2X_1_ENTRY_EQL(unit, del_entry, tab_p, 0)) { 1110 EXT_L2X_1_ENTRY_DELETED_SET(unit, index); 1111 /* Bitmap that indicates to suppress callback */ 1112 if ((flags & SOC_L2X_NO_CALLBACKS)) { 1113 EXT_L2X_1_ENTRY_CALLBACK_SET(unit, index); 1114 } 1115 } 1116 } else if (mem == EXT_L2_ENTRY_2m) { 1117 if (index > soc_mem_index_max(unit, EXT_L2_ENTRY_2m)) { 1118 return SOC_E_PARAM; 1119 } 1120 /* 1121 * validate that the entry in the shadow copy is same as the entry 1122 * deleted. 1123 */ 1124 tab_p = tr3_l2x_data[unit].shadow_tab_ext2 + 1125 (index * tr3_l2x_data[unit].entry_words_ext2); 1126 if (EXT_L2X_2_ENTRY_EQL(unit, del_entry, tab_p, 0)) { 1127 EXT_L2X_2_ENTRY_DELETED_SET(unit, index); 1128 /* Bitmap that indicates to suppress callback */ 1129 if ((flags & SOC_L2X_NO_CALLBACKS)) { 1130 EXT_L2X_2_ENTRY_CALLBACK_SET(unit, index); 1131 } 1132 } 1133 } else { 1134 return SOC_E_PARAM; 1135 } 1136 return SOC_E_NONE; 1137 } 1138 1139 /* 1140 * Function: 1141 * soc_tr3_l2x_stop 1142 * Purpose: 1143 * Stop L2X-related thread 1144 * Parameters: 1145 * unit - unit number. 1146 * Returns: 1147 * SOC_E_XXX 1148 */ 1149 1150 int 1151 soc_tr3_l2x_stop(int unit) 1152 { 1153 soc_control_t *soc = SOC_CONTROL(unit); 1154 int rv = SOC_E_NONE; 1155 soc_timeout_t to; 1156 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT) 1157 int mode; 1158 #endif 1159 1160 LOG_INFO(BSL_LS_SOC_ARL, 1161 (BSL_META_U(unit, 1162 "soc_tr3_l2x_stop: unit=%d\n"), unit)); 1163 1164 tr3_l2x_data[unit].enabled = 0; 1165 SOC_CONTROL_LOCK(unit); 1166 soc->l2x_interval = 0; /* Request exit */ 1167 SOC_CONTROL_UNLOCK(unit); 1168 1169 if (soc->l2x_pid != SAL_THREAD_ERROR) { 1170 /* Wake up thread so it will check the exit flag */ 1171 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT) 1172 mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL); 1173 if (soc_feature(unit, soc_feature_l2_modfifo) && 1174 (mode == L2MODE_FIFO)) { 1175 _soc_l2mod_stop(unit); 1176 } else 1177 #endif 1178 { 1179 sal_sem_give(soc->l2x_notify); 1180 } 1181 1182 /* Give thread a few seconds to wake up and exit */ 1183 if (SAL_BOOT_SIMULATION) { 1184 soc_timeout_init(&to, 30 * 1000000, 0); 1185 } else { 1186 soc_timeout_init(&to, 10 * 1000000, 0); 1187 } 1188 1189 while (soc->l2x_pid != SAL_THREAD_ERROR) { 1190 if (soc_timeout_check(&to)) { 1191 LOG_ERROR(BSL_LS_SOC_L2, 1192 (BSL_META_U(unit, 1193 "soc_tr3_l2x_stop: thread will not exit\n"))); 1194 rv = SOC_E_INTERNAL; 1195 break; 1196 } 1197 } 1198 } 1199 1200 return rv; 1201 } 1202 1203 /* 1204 * Function: 1205 * soc_tr3_l2x_start 1206 * Purpose: 1207 * Initialize shadow table and start L2X thread to maintain it 1208 * Parameters: 1209 * unit - unit number. 1210 * flags - SOC_L2X_FLAG_xxx 1211 * interval - time between resynchronization passes 1212 * Returns: 1213 * SOC_E_MEMORY if can't create thread. 1214 */ 1215 1216 int 1217 soc_tr3_l2x_start(int unit, uint32 flags, sal_usecs_t interval) 1218 { 1219 soc_control_t *soc = SOC_CONTROL(unit); 1220 int pri; 1221 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT) 1222 int mode; 1223 #endif 1224 1225 LOG_INFO(BSL_LS_SOC_ARL, 1226 (BSL_META_U(unit, 1227 "soc_tr3_l2x_start: unit=%d flags=0x%x interval=%d\n"), 1228 unit, flags, interval)); 1229 1230 if (!soc_feature(unit, soc_feature_arl_hashed)) { 1231 return SOC_E_UNAVAIL; 1232 } 1233 1234 if (soc->l2x_interval != 0) { 1235 SOC_IF_ERROR_RETURN(soc_tr3_l2x_stop(unit)); 1236 } 1237 1238 sal_snprintf(soc->l2x_name, sizeof (soc->l2x_name), 1239 "bcmL2X.%d", unit); 1240 1241 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1242 pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50); 1243 soc->l2x_age_hitsa_only = soc_property_get(unit, 1244 spn_L2X_AGE_ONLY_ON_HITSA, 1245 0); 1246 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(BCM_CMICM_SUPPORT) 1247 mode = soc_property_get(unit, spn_L2XMSG_MODE, L2MODE_POLL); 1248 1249 if (mode == L2MODE_FIFO) { 1250 1251 SOC_CONTROL_LOCK(unit); 1252 soc->l2x_mode = mode; 1253 soc->l2x_flags = flags; 1254 soc->l2x_interval = interval; 1255 1256 if (interval == 0) { 1257 SOC_CONTROL_UNLOCK(unit); 1258 return SOC_E_NONE; 1259 } 1260 _soc_l2mod_start(unit, flags, interval); 1261 SOC_CONTROL_UNLOCK(unit); 1262 /* For 'FIFO' mode, set the 'enabled' to '0', 1263 to indicate NO L2 data store. */ 1264 tr3_l2x_data[unit].enabled = 0; 1265 } else 1266 #endif 1267 { 1268 SOC_CONTROL_LOCK(unit); 1269 soc->l2x_mode = L2MODE_POLL; 1270 soc->l2x_flags = flags; 1271 soc->l2x_interval = interval; 1272 1273 if (interval == 0) { 1274 SOC_CONTROL_UNLOCK(unit); 1275 return SOC_E_NONE; 1276 } 1277 soc->l2x_pid = sal_thread_create(soc->l2x_name, 1278 SAL_THREAD_STKSZ, 1279 pri, 1280 _soc_tr3_l2x_thread, 1281 INT_TO_PTR(unit)); 1282 if (soc->l2x_pid == SAL_THREAD_ERROR) { 1283 LOG_ERROR(BSL_LS_SOC_L2, 1284 (BSL_META_U(unit, 1285 "soc_tr3_l2x_start: Could not start L2X thread\n"))); 1286 SOC_CONTROL_UNLOCK(unit); 1287 return SOC_E_MEMORY; 1288 } 1289 SOC_CONTROL_UNLOCK(unit); 1290 } 1291 } 1292 1293 return SOC_E_NONE; 1294 } 1295 1296 /* 1297 * Function: 1298 * _soc_l2x_sync_bucket 1299 * Purpose: 1300 * Compare the old contents of a hash bucket to the 1301 * next contents, make any ARL callbacks that are necessary, 1302 * and sync that bucket in the shadow table. 1303 * Parameters: 1304 * unit - StrataSwitch unit # 1305 * old_bucket - Previous bucket contents (SOC_TR3_L2X_BUCKET_SIZE entries) 1306 * new_bucket - New bucket contents (SOC_TR3_L2X_BUCKET_SIZE entries) 1307 * shadow_hit_bits - perform the notify callback even if 1308 * only hit bits change. 1309 * bucket_index - start index of bucket within chunk 1310 * p_chunk_del_map - pointer to chunk's delete map 1311 * Notes: 1312 * It's necessary to process deletions first, then insertions. 1313 * If an entry moves within the hash bucket, or some field such 1314 * as PORT changes, the application first receives a callback 1315 * for a deletion, and then for an insertion. 1316 */ 1317 1318 STATIC void 1319 _soc_tr3_l2x_sync_bucket(int unit, uint32 *old_bucket, uint32 *new_bucket, 1320 uint8 shadow_hit_bits, int bucket_index, 1321 SHR_BITDCL *p_chunk_del_map, 1322 SHR_BITDCL *p_chunk_cb_map) 1323 { 1324 int io, in, delete_marked, callback_suppress; 1325 uint32 *old_p, *old_ptr, *new_p, *new_ptr; 1326 uint32 kt, kt_new, key_val; 1327 soc_mem_t mem_type_new, mem_type; 1328 soc_field_t field; 1329 1330 /* Since we read everything using a type 1 view only thus, if valid and 1331 present then convert the single type 2 entry split across 2 raw type 1 1332 entries back into a single type 2 entry */ 1333 new_p = new_bucket; 1334 for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; in+=2, 1335 new_p += tr3_l2x_data[unit].entry_words_int * 2) { 1336 if (!L2X_IS_VALID_ENTRY(unit, L2_ENTRY_2m, 1337 new_p, VALID_0f)) { 1338 continue; 1339 } 1340 kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf); 1341 if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1342 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1343 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1344 uint32 tmp[SOC_MAX_MEM_WORDS]; 1345 uint32 *src[4] = {0}; 1346 src[0] = new_p; 1347 src[1] = new_p + tr3_l2x_data[unit].entry_words_int; 1348 soc_mem_base_to_wide_entry_conv(unit, L2_ENTRY_2m, L2_ENTRY_1m, 1349 tmp, src, TYPE_1_TO_TYPE_2); 1350 sal_memcpy(new_p, tmp, soc_mem_entry_bytes(unit, L2_ENTRY_2m)); 1351 } 1352 } 1353 1354 /* 1355 * Process deletions (which will be any entry that was in the bucket 1356 * before but whose key is no longer found anywhere in the bucket) 1357 * and changes (which will be any entry whose key is still found but 1358 * whose associated data (port, etc.) has changed). 1359 */ 1360 1361 old_p = old_bucket; 1362 new_ptr = new_bucket; 1363 for (io = 0; io < SOC_TR3_L2X_BUCKET_SIZE; ) { 1364 /* 1365 * No deletion or change is needed for invalid entries. 1366 */ 1367 if (!soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, VALIDf)) { 1368 io++; 1369 old_p += tr3_l2x_data[unit].entry_words_int; 1370 new_ptr += tr3_l2x_data[unit].entry_words_int; 1371 continue; 1372 } 1373 1374 /* Determine entry type/size */ 1375 mem_type = L2_ENTRY_1m; 1376 kt = soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, KEY_TYPEf); 1377 if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1378 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1379 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1380 mem_type = L2_ENTRY_2m; 1381 } 1382 1383 /* 1384 * Check if the entry has been deleted and is marked for 1385 * delete. 1386 */ 1387 delete_marked = SHR_BITGET(p_chunk_del_map, bucket_index + io); 1388 callback_suppress = SHR_BITGET(p_chunk_cb_map, bucket_index + io); 1389 1390 /* 1391 * Quick check: if the entry is identical, it does not need any 1392 * deletion or change processing. It may be valid or not. 1393 */ 1394 if (L2X_ENTRY_EQL(unit, old_p, new_ptr, 0)) { 1395 /* Entry got learnt again after delete */ 1396 if (delete_marked) { 1397 if (callback_suppress) { 1398 /* Indicate re-learn */ 1399 soc_l2_entry_callback(unit, 0, mem_type, NULL, 1400 (l2_combo_entry_t *) new_ptr); 1401 } else { 1402 /* Indicate delete and re-learn */ 1403 soc_l2_entry_callback(unit, 0, mem_type, 1404 (l2_combo_entry_t *) old_p, NULL); 1405 soc_l2_entry_callback(unit, 0, mem_type, NULL, 1406 (l2_combo_entry_t *) new_ptr); 1407 } 1408 } 1409 goto adv_del_process; 1410 } 1411 1412 /* 1413 * See if the old key still exists anywhere within the bucket. 1414 */ 1415 new_p = new_bucket; 1416 for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; ) { 1417 mem_type_new = L2_ENTRY_1m; 1418 field = VALIDf; 1419 kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf); 1420 if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1421 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1422 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1423 assert(in % 2 == 0); /* wide entry should never be on odd boundary */ 1424 mem_type_new = L2_ENTRY_2m; 1425 field = VALID_0f; 1426 } 1427 if (soc_mem_field32_get(unit, mem_type_new, 1428 new_p, field) && 1429 (soc_mem_compare_key(unit, mem_type_new, 1430 old_p, new_p) == 0)) { 1431 break; 1432 } 1433 if (mem_type == L2_ENTRY_1m) { 1434 if (mem_type_new == L2_ENTRY_1m) { 1435 in++; 1436 new_p += tr3_l2x_data[unit].entry_words_int; 1437 } else { 1438 in += 2; 1439 new_p += tr3_l2x_data[unit].entry_words_int * 2; 1440 } 1441 } else { 1442 in += 2; 1443 new_p += tr3_l2x_data[unit].entry_words_int * 2; 1444 } 1445 } 1446 1447 if (in == SOC_TR3_L2X_BUCKET_SIZE) { 1448 /* It doesn't, so issue a delete. */ 1449 if (!callback_suppress) { 1450 soc_l2_entry_callback(unit, 0, mem_type, (l2_combo_entry_t *)old_p, 1451 NULL); 1452 } 1453 goto adv_del_process; 1454 } 1455 1456 /* 1457 * Check if everything at the new location is the same (ignoring 1458 * hit bit). If so, there is no delete or change processing. 1459 */ 1460 if (!(shadow_hit_bits & L2X_SHADOW_HIT_BITS)) { 1461 if (!(shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 1462 soc_mem_field32_set(unit, mem_type, old_p, HITDAf, 1463 soc_mem_field32_get(unit, mem_type, 1464 new_p, HITDAf)); 1465 } 1466 if (!(shadow_hit_bits & L2X_SHADOW_HIT_SRC)) { 1467 soc_mem_field32_set(unit, mem_type, old_p, HITSAf, 1468 soc_mem_field32_get(unit, mem_type, 1469 new_p, HITSAf)); 1470 } 1471 } 1472 1473 if (L2X_ENTRY_EQL(unit, old_p, new_p, shadow_hit_bits)) { 1474 /* Entry got learnt again after delete */ 1475 if (delete_marked) { 1476 if (callback_suppress) { 1477 /* Indicate re-learn */ 1478 soc_l2_entry_callback(unit, 0, mem_type, NULL, 1479 (l2_combo_entry_t *) new_ptr); 1480 } else { 1481 /* Indicate delete and re-learn */ 1482 soc_l2_entry_callback(unit, 0, mem_type, 1483 (l2_combo_entry_t *) old_p, NULL); 1484 soc_l2_entry_callback(unit, 0, mem_type, NULL, 1485 (l2_combo_entry_t *) new_ptr); 1486 } 1487 } 1488 goto adv_del_process; 1489 } 1490 1491 /* Issue change (delete & insert) */ 1492 if (!callback_suppress) { 1493 soc_l2_entry_callback(unit, 0, mem_type, 1494 (l2_combo_entry_t *) old_p, 1495 (l2_combo_entry_t *) new_p); 1496 } 1497 1498 adv_del_process: 1499 if (mem_type == L2_ENTRY_1m) { 1500 io++; 1501 old_p += tr3_l2x_data[unit].entry_words_int; 1502 new_ptr += tr3_l2x_data[unit].entry_words_int; 1503 } else { 1504 io += 2; 1505 old_p += tr3_l2x_data[unit].entry_words_int * 2; 1506 new_ptr += tr3_l2x_data[unit].entry_words_int * 2; 1507 } 1508 } 1509 1510 /* 1511 * Process insertions, which will be any entry whose key was not in 1512 * the bucket before, but is now. 1513 */ 1514 1515 new_p = new_bucket; 1516 old_ptr = old_bucket; 1517 for (in = 0; in < SOC_TR3_L2X_BUCKET_SIZE; ) { 1518 /* Determine entry type/size */ 1519 mem_type = L2_ENTRY_1m; 1520 kt = soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, KEY_TYPEf); 1521 if ((kt == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1522 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1523 (kt == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1524 mem_type = L2_ENTRY_2m; 1525 } 1526 1527 /* 1528 * Quick check: if the entry is identical, it does not need any 1529 * insertion processing. It may be valid or not. 1530 */ 1531 if (L2X_ENTRY_EQL(unit, new_p, old_ptr, 0)) { 1532 goto adv_ins_process; 1533 } 1534 1535 /* 1536 * No insert needed for invalid entries. 1537 */ 1538 if (!soc_mem_field32_get(unit, L2_ENTRY_1m, new_p, VALIDf)) { 1539 in++; 1540 new_p += tr3_l2x_data[unit].entry_words_int; 1541 old_ptr += tr3_l2x_data[unit].entry_words_int; 1542 continue; 1543 } 1544 1545 /* 1546 * If the same key already existed elsewhere within the bucket, 1547 * it has already been taken care of by the change processing. 1548 */ 1549 1550 old_p = old_bucket; 1551 for (io = 0; io < SOC_TR3_L2X_BUCKET_SIZE; ) { 1552 mem_type_new = L2_ENTRY_1m; 1553 field = VALIDf; 1554 kt_new = soc_mem_field32_get(unit, L2_ENTRY_1m, old_p, KEY_TYPEf); 1555 if ((kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 1556 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 1557 (kt_new == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 1558 assert(io % 2 == 0); /* wide entry should never be on odd boundary */ 1559 mem_type_new = L2_ENTRY_2m; 1560 field = VALID_0f; 1561 } 1562 if (soc_mem_field32_get(unit, mem_type_new, 1563 old_p, field) && 1564 soc_mem_compare_key(unit, mem_type_new, 1565 new_p, old_p) == 0) { 1566 break; 1567 } 1568 if (mem_type == L2_ENTRY_1m) { 1569 if (mem_type_new == L2_ENTRY_1m) { 1570 io++; 1571 old_p += tr3_l2x_data[unit].entry_words_int; 1572 } else { 1573 io += 2; 1574 old_p += tr3_l2x_data[unit].entry_words_int * 2; 1575 } 1576 } else { 1577 io += 2; 1578 old_p += tr3_l2x_data[unit].entry_words_int * 2; 1579 } 1580 } 1581 1582 if (io < SOC_TR3_L2X_BUCKET_SIZE) { 1583 goto adv_ins_process; 1584 } 1585 1586 if (soc_feature(unit, soc_feature_ppa_bypass)) { 1587 if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE) { 1588 if (mem_type == L2_ENTRY_1m) { 1589 key_val = SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE; 1590 } else { 1591 key_val = SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE; 1592 } 1593 if (soc_mem_field32_get(unit, mem_type, new_p, KEY_TYPEf) != 1594 key_val) { 1595 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE; 1596 } 1597 } 1598 } 1599 1600 /* Issue insert */ 1601 delete_marked = SHR_BITGET(p_chunk_del_map, bucket_index + in); 1602 if (!delete_marked) { 1603 soc_l2_entry_callback(unit, 0, mem_type, NULL, 1604 (l2_combo_entry_t *)new_p); 1605 } else { 1606 /* Special case - New entry but marked for deletion by now */ 1607 soc_l2_entry_callback(unit, 0, mem_type, (l2_combo_entry_t *)new_p, 1608 (l2_combo_entry_t *)new_p); 1609 } 1610 1611 adv_ins_process: 1612 if (mem_type == L2_ENTRY_1m) { 1613 in++; 1614 new_p += tr3_l2x_data[unit].entry_words_int; 1615 old_ptr += tr3_l2x_data[unit].entry_words_int; 1616 } else { 1617 in += 2; 1618 new_p += tr3_l2x_data[unit].entry_words_int * 2; 1619 old_ptr += tr3_l2x_data[unit].entry_words_int *2; 1620 } 1621 } 1622 1623 /* Sync shadow copy */ 1624 1625 sal_memcpy(old_bucket, new_bucket, 1626 SOC_TR3_L2X_BUCKET_SIZE * tr3_l2x_data[unit].entry_words_int*4); 1627 } 1628 1629 /* 1630 * Function: 1631 * _soc_tr3_l2x_thread 1632 * Purpose: 1633 * Thread control for L2 shadow table maintenance 1634 * Parameters: 1635 * unit_vp - StrataSwitch unit # (as a void *). 1636 * Returns: 1637 * Nothing 1638 * Notes: 1639 * Exits when l2x_rate is set to zero and semaphore is given. The 1640 * table is processed one chunk at a time (spn_L2XMSG_CHUNKS chunks 1641 * total) in order to reduce memory requirements for the temporary 1642 * DMA buffer and to give the CPU a break from bursts of activity. 1643 */ 1644 1645 STATIC void 1646 _soc_tr3_l2x_thread(void *unit_vp) 1647 { 1648 int unit = PTR_TO_INT(unit_vp); 1649 soc_control_t *soc = SOC_CONTROL(unit); 1650 int rv; 1651 uint32 *shadow_tab = NULL; 1652 uint32 *chunk_buf_int = NULL; 1653 uint32 *chunk_buf_ext1 = NULL, *chunk_buf_ext2 = NULL; 1654 SHR_BITDCL *del_map_int = NULL; 1655 SHR_BITDCL *del_map_ext1 = NULL, *del_map_ext2 = NULL; 1656 SHR_BITDCL *chunk_del_map_int = NULL; 1657 SHR_BITDCL *chunk_del_map_ext1 = NULL, *chunk_del_map_ext2 = NULL; 1658 SHR_BITDCL *cb_map_int = NULL, *cb_map_ext1 = NULL, *cb_map_ext2 = NULL; 1659 SHR_BITDCL *chunk_cb_map_int = NULL; 1660 SHR_BITDCL *chunk_cb_map_ext1 = NULL, *chunk_cb_map_ext2 = NULL; 1661 int index_count_int, index_count_ext1 = 0, index_count_ext2 = 0; 1662 int chunk_count_int = 0, chunk_size_int = 0; 1663 int chunk_count_ext1 = 0, chunk_size_ext1 = 0; 1664 int chunk_count_ext2 = 0, chunk_size_ext2 = 0; 1665 int chunk_index_int = 0, bucket_index, index; 1666 int chunk_index_ext1 = 0, chunk_index_ext2 = 0; 1667 uint32 *tab_p_int = NULL, *buf_p; 1668 uint32 *tab_p_ext1 = NULL, *tab_p_ext2 = NULL; 1669 int interval, delete_marked, callback_suppress; 1670 sal_usecs_t stime, etime; 1671 int iter = 0; 1672 1673 tr3_l2x_data[unit].shadow_tab_int = NULL; 1674 tr3_l2x_data[unit].shadow_tab_ext1 = NULL; 1675 tr3_l2x_data[unit].shadow_tab_ext2 = NULL; 1676 1677 tr3_l2x_data[unit].entry_bytes_int = soc_mem_entry_bytes(unit, L2_ENTRY_1m); 1678 tr3_l2x_data[unit].entry_words_int = soc_mem_entry_words(unit, L2_ENTRY_1m); 1679 1680 index_count_int = soc_mem_index_count(unit, L2_ENTRY_1m); 1681 if (index_count_int <= 0) { 1682 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1683 (BSL_META_U(unit, 1684 "soc_tr3_l2x_thread: Internal L2 table size is 0 \n"))); 1685 tr3_l2x_data[unit].int_avail = FALSE; 1686 goto skip_l2_int; 1687 } else { 1688 tr3_l2x_data[unit].int_avail = TRUE; 1689 } 1690 1691 chunk_count_int = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4); 1692 chunk_size_int = index_count_int / chunk_count_int; 1693 1694 assert(chunk_size_int > 0); 1695 assert(chunk_size_int % SOC_TR3_L2X_BUCKET_SIZE == 0); 1696 1697 shadow_tab = sal_alloc(index_count_int * tr3_l2x_data[unit].entry_words_int * 4, 1698 "l2x_old"); 1699 1700 chunk_buf_int = soc_cm_salloc(unit, 1701 chunk_size_int * tr3_l2x_data[unit].entry_words_int * 4, 1702 "l2x_new"); 1703 1704 del_map_int = sal_alloc(SHR_BITALLOCSIZE(index_count_int), "l2x_delete_map"); 1705 cb_map_int = sal_alloc(SHR_BITALLOCSIZE(index_count_int), "l2x_callback_map"); 1706 1707 chunk_del_map_int = 1708 sal_alloc(SHR_BITALLOCSIZE(chunk_size_int), "l2x_chunk_delete_map"); 1709 chunk_cb_map_int = 1710 sal_alloc(SHR_BITALLOCSIZE(chunk_size_int), "l2x_chunk_callback_map"); 1711 1712 if (shadow_tab == NULL || chunk_buf_int == NULL || 1713 del_map_int == NULL || chunk_del_map_int == NULL || 1714 cb_map_int == NULL || chunk_cb_map_int == NULL) { 1715 LOG_ERROR(BSL_LS_SOC_L2, 1716 (BSL_META_U(unit, 1717 "AbnormalThreadExit:soc_l2x_thread: not enough memory \n"))); 1718 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1719 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY); 1720 goto cleanup_exit; 1721 } 1722 /* 1723 * Start with initially empty shadow table. 1724 */ 1725 1726 sal_memset(shadow_tab, 0, index_count_int * tr3_l2x_data[unit].entry_words_int * 4); 1727 1728 /* 1729 * Clear the delete and callback map. 1730 */ 1731 SHR_BITCLR_RANGE(del_map_int, 0, index_count_int); 1732 SHR_BITCLR_RANGE(cb_map_int, 0, index_count_int); 1733 1734 tr3_l2x_data[unit].shadow_tab_int = shadow_tab; 1735 tr3_l2x_data[unit].del_map_int = del_map_int; 1736 tr3_l2x_data[unit].cb_map_int = cb_map_int; 1737 1738 tab_p_int = shadow_tab; 1739 1740 shadow_tab = NULL; 1741 1742 skip_l2_int: 1743 if (!soc_feature(unit, soc_feature_esm_support)) { 1744 goto skip_l2_ext2; 1745 } 1746 1747 tr3_l2x_data[unit].entry_bytes_ext1 = soc_mem_entry_bytes(unit, EXT_L2_ENTRY_1m); 1748 tr3_l2x_data[unit].entry_words_ext1 = soc_mem_entry_words(unit, EXT_L2_ENTRY_1m); 1749 1750 index_count_ext1 = soc_mem_index_count(unit, EXT_L2_ENTRY_1m); 1751 if (index_count_ext1 <= 0) { 1752 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1753 (BSL_META_U(unit, 1754 "soc_tr3_l2x_thread: External L2_1 table size is 0 \n"))); 1755 tr3_l2x_data[unit].ext1_avail = FALSE; 1756 goto skip_l2_ext1; 1757 } else { 1758 tr3_l2x_data[unit].ext1_avail = TRUE; 1759 } 1760 1761 chunk_count_ext1 = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4); 1762 chunk_size_ext1 = index_count_ext1 / chunk_count_ext1; 1763 1764 assert(chunk_size_ext1 > 0); 1765 assert(chunk_size_ext1 % SOC_TR3_L2X_BUCKET_SIZE == 0); 1766 1767 shadow_tab = sal_alloc(index_count_ext1 * tr3_l2x_data[unit].entry_words_ext1 * 4, 1768 "l2x_old"); 1769 1770 chunk_buf_ext1 = soc_cm_salloc(unit, chunk_size_ext1 * 1771 tr3_l2x_data[unit].entry_words_ext1 * 4, 1772 "l2x_new"); 1773 1774 del_map_ext1 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext1), "l2x_delete_map"); 1775 cb_map_ext1 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext1), "l2x_callback_map"); 1776 1777 chunk_del_map_ext1 = 1778 sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext1), "l2x_chunk_delete_map"); 1779 chunk_cb_map_ext1 = 1780 sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext1), "l2x_chunk_callback_map"); 1781 1782 if (shadow_tab == NULL || chunk_buf_ext1 == NULL || 1783 del_map_ext1 == NULL || chunk_del_map_ext1 == NULL || 1784 cb_map_ext1 == NULL || chunk_cb_map_ext1 == NULL) { 1785 LOG_ERROR(BSL_LS_SOC_L2, 1786 (BSL_META_U(unit, 1787 "AbnormalThreadExit:soc_l2x_thread: not enough memory \n"))); 1788 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1789 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY); 1790 goto cleanup_exit; 1791 } 1792 /* 1793 * Start with initially empty shadow table. 1794 */ 1795 sal_memset(shadow_tab, 0, index_count_ext1 * tr3_l2x_data[unit].entry_words_ext1 * 4); 1796 buf_p = shadow_tab; 1797 for (index = 0; index < index_count_ext1; index ++) { 1798 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, buf_p, FREEf, 1); 1799 buf_p += tr3_l2x_data[unit].entry_words_ext1; 1800 } 1801 1802 /* 1803 * Clear the delete and callback map. 1804 */ 1805 SHR_BITCLR_RANGE(del_map_ext1, 0, index_count_ext1); 1806 SHR_BITCLR_RANGE(cb_map_ext1, 0, index_count_ext1); 1807 1808 tr3_l2x_data[unit].shadow_tab_ext1 = shadow_tab; 1809 tr3_l2x_data[unit].del_map_ext1 = del_map_ext1; 1810 tr3_l2x_data[unit].cb_map_ext1 = cb_map_ext1; 1811 1812 tab_p_ext1 = shadow_tab; 1813 1814 shadow_tab = NULL; 1815 1816 skip_l2_ext1: 1817 tr3_l2x_data[unit].entry_bytes_ext2 = soc_mem_entry_bytes(unit, EXT_L2_ENTRY_2m); 1818 tr3_l2x_data[unit].entry_words_ext2 = soc_mem_entry_words(unit, EXT_L2_ENTRY_2m); 1819 1820 index_count_ext2 = soc_mem_index_count(unit, EXT_L2_ENTRY_2m); 1821 if (index_count_ext2 <= 0) { 1822 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1823 (BSL_META_U(unit, 1824 "soc_tr3_l2x_thread: External L2_2 table size is 0 \n"))); 1825 tr3_l2x_data[unit].ext2_avail = FALSE; 1826 goto skip_l2_ext2; 1827 } else { 1828 tr3_l2x_data[unit].ext2_avail = TRUE; 1829 } 1830 1831 chunk_count_ext2 = soc_property_get(unit, spn_L2XMSG_CHUNKS, 4); 1832 chunk_size_ext2 = index_count_ext2 / chunk_count_ext2; 1833 1834 assert(chunk_size_ext2 > 0); 1835 assert(chunk_size_ext2 % SOC_TR3_L2X_BUCKET_SIZE == 0); 1836 1837 shadow_tab = sal_alloc(index_count_ext2 * tr3_l2x_data[unit].entry_words_ext2 * 4, 1838 "l2x_old"); 1839 1840 chunk_buf_ext2 = soc_cm_salloc(unit, chunk_size_ext2 * 1841 tr3_l2x_data[unit].entry_words_ext2 * 4, 1842 "l2x_new"); 1843 1844 del_map_ext2 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext2), "l2x_delete_map"); 1845 cb_map_ext2 = sal_alloc(SHR_BITALLOCSIZE(index_count_ext2), "l2x_callback_map"); 1846 1847 chunk_del_map_ext2 = 1848 sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext2), "l2x_chunk_delete_map"); 1849 chunk_cb_map_ext2 = 1850 sal_alloc(SHR_BITALLOCSIZE(chunk_size_ext2), "l2x_chunk_callback_map"); 1851 1852 if (shadow_tab == NULL || chunk_buf_ext2 == NULL || 1853 del_map_ext2 == NULL || chunk_del_map_ext2 == NULL || 1854 cb_map_ext2 == NULL || chunk_cb_map_ext2 == NULL) { 1855 LOG_ERROR(BSL_LS_SOC_L2, 1856 (BSL_META_U(unit, 1857 "AbnormalThreadExit:soc_l2x_thread: not enough memory \n"))); 1858 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1859 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_MEMORY); 1860 goto cleanup_exit; 1861 } 1862 /* 1863 * Start with initially empty shadow table. 1864 */ 1865 sal_memset(shadow_tab, 0, index_count_ext2 * tr3_l2x_data[unit].entry_words_ext2 * 4); 1866 buf_p = shadow_tab; 1867 for (index = 0; index < index_count_ext2; index ++) { 1868 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, buf_p, FREEf, 1); 1869 buf_p += tr3_l2x_data[unit].entry_words_ext2; 1870 } 1871 1872 /* 1873 * Clear the delete and callback map. 1874 */ 1875 SHR_BITCLR_RANGE(del_map_ext2, 0, index_count_ext2); 1876 SHR_BITCLR_RANGE(cb_map_ext2, 0, index_count_ext2); 1877 1878 tr3_l2x_data[unit].shadow_tab_ext2 = shadow_tab; 1879 tr3_l2x_data[unit].del_map_ext2 = del_map_ext2; 1880 tr3_l2x_data[unit].cb_map_ext2 = cb_map_ext2; 1881 1882 tab_p_ext2 = shadow_tab; 1883 1884 shadow_tab = NULL; 1885 1886 skip_l2_ext2: 1887 if (tr3_l2x_data[unit].int_avail == FALSE && 1888 tr3_l2x_data[unit].ext1_avail == FALSE && 1889 tr3_l2x_data[unit].ext2_avail == FALSE) { 1890 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1891 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, SOC_E_EMPTY); 1892 goto no_cleanup_exit; 1893 } 1894 /* 1895 * For 'POLL' mode, set the 'enabled' to '1', 1896 * to indicate L2 data store. 1897 */ 1898 tr3_l2x_data[unit].enabled = 1; 1899 1900 while ((interval = soc->l2x_interval) != 0) { 1901 /* 1902 * Read the next chunk of the L2 table using Table DMA. 1903 */ 1904 stime = sal_time_usecs(); 1905 1906 /* 1907 * If running for the first time wait for 1908 * duration = interval 1909 */ 1910 if (!iter) { 1911 goto continue_loop; 1912 } 1913 1914 if (tr3_l2x_data[unit].int_avail == FALSE) { 1915 goto skip_l2_int_loop; 1916 } 1917 LOG_VERBOSE(BSL_LS_SOC_ARL, 1918 (BSL_META_U(unit, 1919 "soc_l2x_thread: Process INT %d-%d\n"), 1920 chunk_index_int, chunk_index_int + chunk_size_int - 1)); 1921 SOC_MEM_L2_INT_LOCK(unit); 1922 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 1923 LOG_ERROR(BSL_LS_SOC_L2, 1924 (BSL_META_U(unit, 1925 "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n"))); 1926 SOC_MEM_L2_INT_UNLOCK(unit); 1927 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1928 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, 1929 SOC_E_RESOURCE); 1930 goto cleanup_exit; 1931 } 1932 1933 if ((rv = soc_mem_read_range(unit, L2_ENTRY_1m, 1934 MEM_BLOCK_ANY, chunk_index_int, 1935 chunk_index_int + chunk_size_int - 1, 1936 chunk_buf_int)) < 0) { 1937 SOC_L2_DEL_SYNC_UNLOCK(soc); 1938 SOC_MEM_L2_INT_UNLOCK(unit); 1939 LOG_ERROR(BSL_LS_SOC_L2, 1940 (BSL_META_U(unit, 1941 "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"), 1942 soc_errmsg(rv))); 1943 1944 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 1945 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv); 1946 1947 goto cleanup_exit; 1948 } else { 1949 SHR_BITCOPY_RANGE(chunk_del_map_int, 0, del_map_int, chunk_index_int, 1950 chunk_size_int); 1951 SHR_BITCOPY_RANGE(chunk_cb_map_int, 0, cb_map_int, chunk_index_int, 1952 chunk_size_int); 1953 1954 SHR_BITCLR_RANGE(del_map_int, chunk_index_int, chunk_size_int); 1955 SHR_BITCLR_RANGE(cb_map_int, chunk_index_int, chunk_size_int); 1956 1957 SOC_L2_DEL_SYNC_UNLOCK(soc); 1958 SOC_MEM_L2_INT_UNLOCK(unit); 1959 1960 /* 1961 * Scan, compare, and sync the old and new chunks one bucket 1962 * at a time. 1963 */ 1964 buf_p = chunk_buf_int; 1965 for (bucket_index = 0; bucket_index < chunk_size_int; 1966 bucket_index += SOC_TR3_L2X_BUCKET_SIZE) { 1967 _soc_tr3_l2x_sync_bucket(unit, tab_p_int, buf_p, 1968 soc->l2x_shadow_hit_bits, 1969 bucket_index, chunk_del_map_int, 1970 chunk_cb_map_int); 1971 tab_p_int += tr3_l2x_data[unit].entry_words_int * SOC_TR3_L2X_BUCKET_SIZE; 1972 buf_p += tr3_l2x_data[unit].entry_words_int * SOC_TR3_L2X_BUCKET_SIZE; 1973 } 1974 1975 if ((chunk_index_int += chunk_size_int) >= index_count_int) { 1976 chunk_index_int = 0; 1977 tab_p_int = tr3_l2x_data[unit].shadow_tab_int; 1978 } 1979 } 1980 1981 skip_l2_int_loop: 1982 if (!soc_feature(unit, soc_feature_esm_support)) { 1983 goto continue_loop; 1984 } 1985 if (tr3_l2x_data[unit].ext1_avail == FALSE) { 1986 goto skip_l2_ext1_loop; 1987 } 1988 LOG_VERBOSE(BSL_LS_SOC_ARL, 1989 (BSL_META_U(unit, 1990 "soc_l2x_thread: Process EXT1 %d-%d\n"), 1991 chunk_index_ext1, chunk_index_ext1 + chunk_size_ext1 - 1)); 1992 1993 /* First work on EXT_L2_ENTRY_1 */ 1994 SOC_MEM_L2_EXT_1_LOCK(unit); 1995 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 1996 LOG_ERROR(BSL_LS_SOC_L2, 1997 (BSL_META_U(unit, 1998 "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n"))); 1999 SOC_MEM_L2_INT_UNLOCK(unit); 2000 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 2001 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, 2002 SOC_E_RESOURCE); 2003 goto cleanup_exit; 2004 } 2005 2006 if ((rv = soc_mem_read_range(unit, EXT_L2_ENTRY_1m, 2007 MEM_BLOCK_ANY, chunk_index_ext1, 2008 chunk_index_ext1 + chunk_size_ext1 - 1, 2009 chunk_buf_ext1)) < 0) { 2010 SOC_L2_DEL_SYNC_UNLOCK(soc); 2011 SOC_MEM_L2_EXT_1_UNLOCK(unit); 2012 LOG_ERROR(BSL_LS_SOC_L2, 2013 (BSL_META_U(unit, 2014 "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"), 2015 soc_errmsg(rv))); 2016 2017 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 2018 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv); 2019 2020 goto cleanup_exit; 2021 } else { 2022 SHR_BITCOPY_RANGE(chunk_del_map_ext1, 0, del_map_ext1, chunk_index_ext1, 2023 chunk_size_ext1); 2024 SHR_BITCOPY_RANGE(chunk_cb_map_ext1, 0, cb_map_ext1, chunk_index_ext1, 2025 chunk_size_ext1); 2026 2027 SHR_BITCLR_RANGE(del_map_ext1, chunk_index_ext1, chunk_size_ext1); 2028 SHR_BITCLR_RANGE(cb_map_ext1, chunk_index_ext1, chunk_size_ext1); 2029 2030 SOC_L2_DEL_SYNC_UNLOCK(soc); 2031 SOC_MEM_L2_EXT_1_UNLOCK(unit); 2032 2033 /* 2034 * Scan, compare, and sync the old and new chunks. 2035 */ 2036 buf_p = chunk_buf_ext1; 2037 for (index = 0; index < chunk_size_ext1; index ++) { 2038 /* Check if old entry was free */ 2039 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, tab_p_ext1, FREEf)) { 2040 /* if new entry is used then issue insert cb */ 2041 if (!soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, buf_p, FREEf)) { 2042 delete_marked = SHR_BITGET(chunk_del_map_ext1, index); 2043 if (!delete_marked) { 2044 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, NULL, 2045 (l2_combo_entry_t *)buf_p); 2046 } else { 2047 /* Special case - New entry but marked for deletion by now */ 2048 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 2049 (l2_combo_entry_t *)buf_p, 2050 (l2_combo_entry_t *)buf_p); 2051 } 2052 } 2053 } else { 2054 /* If the new entry is free then issue del cb */ 2055 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_1m, buf_p, FREEf)) { 2056 callback_suppress = SHR_BITGET(chunk_cb_map_ext1, index); 2057 if (!callback_suppress) { 2058 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 2059 (l2_combo_entry_t *)tab_p_ext1, NULL); 2060 } 2061 } else { 2062 /* If new entry is different then issue a replace (del+ins) cb */ 2063 delete_marked = SHR_BITGET(chunk_del_map_ext1, index); 2064 callback_suppress = SHR_BITGET(chunk_cb_map_ext1, index); 2065 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_BITS)) { 2066 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 2067 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, tab_p_ext1, 2068 HITDAf, soc_mem_field32_get(unit, 2069 EXT_L2_ENTRY_1m, 2070 buf_p, HITDAf)); 2071 } 2072 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_SRC)) { 2073 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, tab_p_ext1, 2074 HITSAf, soc_mem_field32_get(unit, 2075 EXT_L2_ENTRY_1m, 2076 buf_p, HITSAf)); 2077 } 2078 } 2079 if (EXT_L2X_1_ENTRY_EQL(unit, tab_p_ext1, buf_p, 2080 soc->l2x_shadow_hit_bits)) { 2081 if (delete_marked && !callback_suppress) { 2082 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 2083 (l2_combo_entry_t *)tab_p_ext1, NULL); 2084 } 2085 } else { 2086 if (delete_marked && !callback_suppress) { 2087 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_1m, 2088 (l2_combo_entry_t *)tab_p_ext1, 2089 (l2_combo_entry_t *)buf_p); 2090 } 2091 } 2092 } 2093 } 2094 sal_memcpy(tab_p_ext1, buf_p, tr3_l2x_data[unit].entry_words_ext1 * 4); 2095 tab_p_ext1 += tr3_l2x_data[unit].entry_words_ext1; 2096 buf_p += tr3_l2x_data[unit].entry_words_ext1; 2097 } 2098 2099 if ((chunk_index_ext1 += chunk_size_ext1) >= index_count_ext1) { 2100 chunk_index_ext1 = 0; 2101 tab_p_ext1 = tr3_l2x_data[unit].shadow_tab_ext1; 2102 } 2103 } 2104 2105 skip_l2_ext1_loop: 2106 if (tr3_l2x_data[unit].ext2_avail == FALSE) { 2107 goto continue_loop; 2108 } 2109 LOG_VERBOSE(BSL_LS_SOC_ARL, 2110 (BSL_META_U(unit, 2111 "soc_l2x_thread: Process EXT2 %d-%d\n"), 2112 chunk_index_ext2, chunk_index_ext2 + chunk_size_ext2 - 1)); 2113 /* Then work on EXT_L2_ENTRY_2 */ 2114 SOC_MEM_L2_EXT_2_LOCK(unit); 2115 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 2116 LOG_ERROR(BSL_LS_SOC_L2, 2117 (BSL_META_U(unit, 2118 "AbnormalThreadExit:soc_l2x_thread: unable to take mutex\n"))); 2119 SOC_MEM_L2_INT_UNLOCK(unit); 2120 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 2121 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, 2122 SOC_E_RESOURCE); 2123 goto cleanup_exit; 2124 } 2125 2126 if ((rv = soc_mem_read_range(unit, EXT_L2_ENTRY_2m, 2127 MEM_BLOCK_ANY, chunk_index_ext2, 2128 chunk_index_ext2 + chunk_size_ext2 - 1, 2129 chunk_buf_ext2)) < 0) { 2130 SOC_L2_DEL_SYNC_UNLOCK(soc); 2131 SOC_MEM_L2_EXT_2_UNLOCK(unit); 2132 LOG_ERROR(BSL_LS_SOC_L2, 2133 (BSL_META_U(unit, 2134 "AbnormalThreadExit:soc_l2x_thread: DMA failed: %s\n"), 2135 soc_errmsg(rv))); 2136 2137 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 2138 SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv); 2139 2140 goto cleanup_exit; 2141 } else { 2142 SHR_BITCOPY_RANGE(chunk_del_map_ext2, 0, del_map_ext2, chunk_index_ext2, 2143 chunk_size_ext2); 2144 SHR_BITCOPY_RANGE(chunk_cb_map_ext2, 0, cb_map_ext2, chunk_index_ext2, 2145 chunk_size_ext2); 2146 2147 SHR_BITCLR_RANGE(del_map_ext2, chunk_index_ext2, chunk_size_ext2); 2148 SHR_BITCLR_RANGE(cb_map_ext2, chunk_index_ext2, chunk_size_ext2); 2149 2150 SOC_L2_DEL_SYNC_UNLOCK(soc); 2151 SOC_MEM_L2_EXT_2_UNLOCK(unit); 2152 2153 /* 2154 * Scan, compare, and sync the old and new chunks. 2155 */ 2156 buf_p = chunk_buf_ext2; 2157 for (index = 0; index < chunk_size_ext2; index ++) { 2158 /* Check if old entry was free */ 2159 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, tab_p_ext2, FREEf)) { 2160 /* if new entry is used then issue insert cb */ 2161 if (!soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, buf_p, FREEf)) { 2162 delete_marked = SHR_BITGET(chunk_del_map_ext2, index); 2163 if (!delete_marked) { 2164 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, NULL, 2165 (l2_combo_entry_t *)buf_p); 2166 } 2167 } 2168 } else { 2169 /* If the new entry is free then issue del cb */ 2170 if (soc_mem_field32_get(unit, EXT_L2_ENTRY_2m, buf_p, FREEf)) { 2171 callback_suppress = SHR_BITGET(chunk_cb_map_ext2, index); 2172 if (!callback_suppress) { 2173 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, 2174 (l2_combo_entry_t *)tab_p_ext2, NULL); 2175 } 2176 } else { 2177 /* If new entry is different then issue a replace (del+ins) cb */ 2178 delete_marked = SHR_BITGET(chunk_del_map_ext2, index); 2179 callback_suppress = SHR_BITGET(chunk_cb_map_ext2, index); 2180 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_BITS)) { 2181 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_DST)) { 2182 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, tab_p_ext2, 2183 HITDAf, soc_mem_field32_get(unit, 2184 EXT_L2_ENTRY_2m, 2185 buf_p, HITDAf)); 2186 } 2187 if (!(soc->l2x_shadow_hit_bits & L2X_SHADOW_HIT_SRC)) { 2188 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, tab_p_ext2, 2189 HITSAf, soc_mem_field32_get(unit, 2190 EXT_L2_ENTRY_2m, 2191 buf_p, HITSAf)); 2192 } 2193 } 2194 if (EXT_L2X_2_ENTRY_EQL(unit, tab_p_ext2, buf_p, 2195 soc->l2x_shadow_hit_bits)) { 2196 if (delete_marked && !callback_suppress) { 2197 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, 2198 (l2_combo_entry_t *)tab_p_ext2, NULL); 2199 } 2200 } else { 2201 if (delete_marked && !callback_suppress) { 2202 soc_l2_entry_callback(unit, 0, EXT_L2_ENTRY_2m, 2203 (l2_combo_entry_t *)tab_p_ext2, 2204 (l2_combo_entry_t *)buf_p); 2205 } 2206 } 2207 } 2208 } 2209 sal_memcpy(tab_p_ext2, buf_p, tr3_l2x_data[unit].entry_words_ext2 * 4); 2210 tab_p_ext2 += tr3_l2x_data[unit].entry_words_ext2; 2211 buf_p += tr3_l2x_data[unit].entry_words_ext2; 2212 } 2213 2214 if ((chunk_index_ext2 += chunk_size_ext2) >= index_count_ext2) { 2215 chunk_index_ext2 = 0; 2216 tab_p_ext2 = tr3_l2x_data[unit].shadow_tab_ext2; 2217 } 2218 } 2219 continue_loop: 2220 etime = sal_time_usecs(); 2221 2222 /* 2223 * Implement the sleep using a semaphore timeout so if the task 2224 * is requested to exit, it can do so immediately. 2225 */ 2226 2227 LOG_VERBOSE(BSL_LS_SOC_ARL, 2228 (BSL_META_U(unit, 2229 "soc_l2x_thread: unit=%d: done in %d usec\n"), unit, 2230 SAL_USECS_SUB(etime, stime))); 2231 2232 sal_sem_take(soc->l2x_notify, interval / (chunk_count_int ? 2233 chunk_count_int : chunk_count_ext1 ? chunk_count_ext1 : 2234 chunk_count_ext2 ? chunk_count_ext2 : 4)); 2235 2236 if (!iter) { 2237 iter++; 2238 } 2239 } 2240 2241 cleanup_exit: 2242 (void)sal_sem_take(soc->l2x_lock, sal_sem_FOREVER); 2243 2244 if (chunk_buf_int != NULL) { 2245 soc_cm_sfree(unit, chunk_buf_int); 2246 } 2247 2248 if (shadow_tab != NULL) { 2249 soc_cm_sfree(unit, shadow_tab); 2250 shadow_tab = NULL; 2251 } 2252 2253 if (tr3_l2x_data[unit].shadow_tab_int != NULL) { 2254 sal_free(tr3_l2x_data[unit].shadow_tab_int); 2255 tr3_l2x_data[unit].shadow_tab_int = NULL; 2256 } 2257 2258 if (del_map_int != NULL) { 2259 sal_free(del_map_int); 2260 tr3_l2x_data[unit].del_map_int = NULL; 2261 } 2262 2263 if (chunk_del_map_int != NULL) { 2264 sal_free(chunk_del_map_int); 2265 } 2266 2267 if (cb_map_int != NULL) { 2268 sal_free(cb_map_int); 2269 tr3_l2x_data[unit].cb_map_int = NULL; 2270 } 2271 2272 if (chunk_cb_map_int != NULL) { 2273 sal_free(chunk_cb_map_int); 2274 } 2275 2276 if (!soc_feature(unit, soc_feature_esm_support)) { 2277 goto skip_cleanup_l2_ext; 2278 } 2279 2280 if (chunk_buf_ext1 != NULL) { 2281 soc_cm_sfree(unit, chunk_buf_ext1); 2282 } 2283 2284 if (tr3_l2x_data[unit].shadow_tab_ext1 != NULL) { 2285 sal_free(tr3_l2x_data[unit].shadow_tab_ext1); 2286 tr3_l2x_data[unit].shadow_tab_ext1 = NULL; 2287 } 2288 2289 if (del_map_ext1 != NULL) { 2290 sal_free(del_map_ext1); 2291 tr3_l2x_data[unit].del_map_ext1 = NULL; 2292 } 2293 2294 if (chunk_del_map_ext1 != NULL) { 2295 sal_free(chunk_del_map_ext1); 2296 } 2297 2298 if (cb_map_ext1 != NULL) { 2299 sal_free(cb_map_ext1); 2300 tr3_l2x_data[unit].cb_map_ext1 = NULL; 2301 } 2302 2303 if (chunk_cb_map_ext1 != NULL) { 2304 sal_free(chunk_cb_map_ext1); 2305 } 2306 2307 if (chunk_buf_ext2 != NULL) { 2308 soc_cm_sfree(unit, chunk_buf_ext2); 2309 } 2310 2311 if (tr3_l2x_data[unit].shadow_tab_ext2 != NULL) { 2312 sal_free(tr3_l2x_data[unit].shadow_tab_ext2); 2313 tr3_l2x_data[unit].shadow_tab_ext2 = NULL; 2314 } 2315 2316 if (del_map_ext2 != NULL) { 2317 sal_free(del_map_ext2); 2318 tr3_l2x_data[unit].del_map_ext2 = NULL; 2319 } 2320 2321 if (chunk_del_map_ext2 != NULL) { 2322 sal_free(chunk_del_map_ext2); 2323 } 2324 2325 if (cb_map_ext2 != NULL) { 2326 sal_free(cb_map_ext2); 2327 tr3_l2x_data[unit].cb_map_ext2 = NULL; 2328 } 2329 2330 if (chunk_cb_map_ext2 != NULL) { 2331 sal_free(chunk_cb_map_ext2); 2332 } 2333 2334 skip_cleanup_l2_ext: 2335 (void)sal_sem_give(soc->l2x_lock); 2336 2337 no_cleanup_exit: 2338 LOG_INFO(BSL_LS_SOC_ARL, 2339 (BSL_META_U(unit, 2340 "soc_l2x_thread: exiting\n"))); 2341 2342 soc->l2x_pid = SAL_THREAD_ERROR; 2343 sal_thread_exit(0); 2344 } 2345 2346 void 2347 soc_tr3_l2mod_fifo_process(int unit, uint32 flags, l2_mod_fifo_entry_t *entry) 2348 { 2349 uint32 op; 2350 soc_mem_t mem_type = INVALIDm; 2351 uint32 fval[SOC_MAX_MEM_FIELD_WORDS], fval1[SOC_MAX_MEM_FIELD_WORDS]; 2352 l2_combo_entry_t l2_entry, old_l2_entry, temp_l2_entry; 2353 uint32 key_type; 2354 int station_move = FALSE; 2355 int assoc_data_length = 0; 2356 LOG_VERBOSE(BSL_LS_SOC_ARL, 2357 (BSL_META_U(unit, 2358 "Processing L2 MOD FIFO message..\n"))); 2359 2360 if (soc_L2_MOD_FIFOm_field32_get(unit, entry, EXTERNAL_L2_ENTRYf)) { 2361 if (soc_feature(unit, soc_feature_esm_support)) { 2362 if (soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_WIDTHf)) { 2363 mem_type = EXT_L2_ENTRY_2m; 2364 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf, 2365 l2_entry.ext_l2_entry_2.entry_data); 2366 2367 LOG_INFO(BSL_LS_SOC_ARL, 2368 (BSL_META_U(unit, 2369 "External L2 entry type 2.\n"))); 2370 } else { 2371 mem_type = EXT_L2_ENTRY_1m; 2372 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf, 2373 l2_entry.ext_l2_entry_1.entry_data); 2374 2375 LOG_INFO(BSL_LS_SOC_ARL, 2376 (BSL_META_U(unit, 2377 "External L2 entry type 1.\n"))); 2378 } 2379 } else { 2380 LOG_ERROR(BSL_LS_SOC_L2, 2381 (BSL_META_U(unit, 2382 "Unexpected external L2 entry data in L2 MOD FIFO !!\n"))); 2383 } 2384 } else { 2385 if (soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_WIDTHf)) { 2386 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf, 2387 l2_entry.l2_entry_2.entry_data); 2388 mem_type = L2_ENTRY_2m; 2389 LOG_INFO(BSL_LS_SOC_ARL, 2390 (BSL_META_U(unit, 2391 "Internal L2 entry type 2.\n"))); 2392 } else { 2393 soc_L2_MOD_FIFOm_field_get(unit, entry, L2_ENTRYf, 2394 l2_entry.l2_entry_1.entry_data); 2395 mem_type = L2_ENTRY_1m; 2396 LOG_INFO(BSL_LS_SOC_ARL, 2397 (BSL_META_U(unit, 2398 "Internal L2 entry type 1.\n"))); 2399 } 2400 } 2401 2402 if (soc_L2_MOD_FIFOm_field32_get(unit, entry, STATION_MOVEf)) { 2403 if (mem_type == L2_ENTRY_1m) { 2404 /* following is to handle the reserved bit in the actual l2 entry 2405 that does not exist in the mod fifo data so we convert/split the 2406 fifo data into l2 entry by copying over parts of fifo data */ 2407 soc_mem_field_get(unit, L2_ENTRY_1m, l2_entry.l2_entry_1.entry_data, KEY_TYPEf, 2408 &key_type); 2409 if (key_type == 0 || key_type == 2) { 2410 /*It is only acceptable for Bridge and VFI mode*/ 2411 sal_memcpy(&old_l2_entry.l2_entry_1, &l2_entry.l2_entry_1, 2412 sizeof(l2_entry.l2_entry_1)); 2413 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2414 REPLACED_ASSOC_DATAf, fval); 2415 soc_mem_field_set(unit, L2_ENTRY_1m, temp_l2_entry.l2_entry_1.entry_data, 2416 L2__DATAf, fval); 2417 soc_mem_field_set(unit, L2_ENTRY_1m, old_l2_entry.l2_entry_1.entry_data, 2418 L2__DATA_Af, 2419 soc_mem_field_get(unit, L2_ENTRY_1m, 2420 temp_l2_entry.l2_entry_1.entry_data, 2421 L2__DATA_Af, fval)); 2422 soc_mem_field_set(unit, L2_ENTRY_1m, old_l2_entry.l2_entry_1.entry_data, 2423 L2__DATA_Bf, 2424 soc_mem_field_get(unit, L2_ENTRY_1m, 2425 temp_l2_entry.l2_entry_1.entry_data, 2426 L2__DUMMYf, fval)); 2427 } 2428 } else if (mem_type == L2_ENTRY_2m) { 2429 /* following is needed because associated data is not contiguous in 2430 l2 double wide entry but it is contiguous in the mod fifo data so 2431 we convert/split the fifo data into l2 entry by copying over parts 2432 of fifo data */ 2433 sal_memcpy(&old_l2_entry.l2_entry_2, &l2_entry.l2_entry_2, 2434 sizeof(l2_entry.l2_entry_2)); 2435 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2436 REPLACED_ASSOC_DATAf, fval); 2437 soc_mem_field_set(unit, L2_ENTRY_2m, temp_l2_entry.l2_entry_2.entry_data, 2438 L2__DATAf, fval); 2439 soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 2440 L2__DATA_0f, 2441 soc_mem_field_get(unit, L2_ENTRY_2m, 2442 temp_l2_entry.l2_entry_2.entry_data, 2443 L2__DATA_0f, fval)); 2444 soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 2445 L2__DATA_1_Af, 2446 soc_mem_field_get(unit, L2_ENTRY_2m, 2447 temp_l2_entry.l2_entry_2.entry_data, 2448 L2__DUMMY0f, fval)); 2449 soc_mem_field_set(unit, L2_ENTRY_2m, old_l2_entry.l2_entry_2.entry_data, 2450 L2__DATA_1_Bf, 2451 soc_mem_field_get(unit, L2_ENTRY_2m, 2452 temp_l2_entry.l2_entry_2.entry_data, 2453 L2__DUMMY1f, fval)); 2454 } 2455 } 2456 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 2457 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 2458 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 2459 } 2460 if (mem_type == INVALIDm) { 2461 LOG_ERROR(BSL_LS_SOC_L2, 2462 (BSL_META_U(unit, 2463 "Unable to determine L2 mem type !!\n"))); 2464 return; 2465 } 2466 op = soc_L2_MOD_FIFOm_field32_get(unit, entry, OPERATIONf); 2467 if ((op == 2 || op == 6 || op == 8) && 2468 (mem_type == EXT_L2_ENTRY_1m || mem_type == EXT_L2_ENTRY_2m)) { 2469 (void)soc_triumph3_ext_l2_entry_update(unit, mem_type, 2470 soc_L2_MOD_FIFOm_field32_get(unit, entry, ENTRY_ADRf), 2471 (op == 2) ? &l2_entry : NULL); 2472 } 2473 2474 switch (op) { 2475 case 0: /* L2_DELETE */ 2476 case 6: /* L2_BULK_DELETE */ 2477 case 8: /* L2_BULK_AGE */ 2478 soc_l2_entry_callback(unit, 0, mem_type, &l2_entry, NULL); 2479 break; 2480 case 7: /* L2_BULK_REPLACE */ 2481 soc_l2_entry_callback(unit, 0, mem_type, &l2_entry, &l2_entry); 2482 break; 2483 case 1: /* L2_INSERT */ 2484 case 2: /* LEARN */ 2485 if (soc_L2_MOD_FIFOm_field32_get(unit, entry, STATION_MOVEf)) { 2486 /* The following is a workaround for L2_MOD_FIFO. The false callback caused 2487 by false staion move is avoided. */ 2488 if (mem_type == L2_ENTRY_1m) { 2489 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, L2_ENTRY_1m, 2490 L2__DATAf)); 2491 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2492 REPLACED_ASSOC_DATAf, fval); 2493 soc_mem_field_get(unit, L2_ENTRY_1m, l2_entry.l2_entry_1.entry_data, 2494 L2__DATAf, fval1); 2495 station_move = sal_memcmp(fval1, fval, assoc_data_length); 2496 2497 } else if (mem_type == L2_ENTRY_2m) { 2498 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, L2_ENTRY_2m, 2499 L2__DATAf)); 2500 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2501 REPLACED_ASSOC_DATAf, fval); 2502 soc_mem_field_get(unit, L2_ENTRY_2m, l2_entry.l2_entry_2.entry_data, 2503 L2__DATAf, fval1); 2504 station_move = sal_memcmp(fval1, fval, assoc_data_length); 2505 2506 } else if (mem_type == EXT_L2_ENTRY_1m) { 2507 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, EXT_L2_ENTRY_1m, 2508 DATAf)); 2509 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2510 REPLACED_ASSOC_DATAf, fval); 2511 soc_mem_field_get(unit, EXT_L2_ENTRY_1m, l2_entry.ext_l2_entry_1.entry_data, 2512 DATAf, fval1); 2513 station_move = sal_memcmp(fval1, fval, assoc_data_length); 2514 } else if (mem_type == EXT_L2_ENTRY_2m) { 2515 assoc_data_length = BITS2BYTES(soc_mem_field_length(unit, EXT_L2_ENTRY_2m, 2516 DATAf)); 2517 soc_L2_MOD_FIFOm_field_get(unit, (uint32 *)entry, 2518 REPLACED_ASSOC_DATAf, fval); 2519 soc_mem_field_get(unit, EXT_L2_ENTRY_2m, l2_entry.ext_l2_entry_2.entry_data, 2520 DATAf, fval1); 2521 station_move = sal_memcmp(fval1, fval, assoc_data_length); 2522 } 2523 if (station_move) { 2524 soc_l2_entry_callback(unit, 0, mem_type, &old_l2_entry, &l2_entry); 2525 } 2526 } else { 2527 soc_l2_entry_callback(unit, 0, mem_type, NULL, &l2_entry); 2528 } 2529 break; 2530 default: 2531 break; 2532 } 2533 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityVerbose, unit)) { 2534 soc_mem_entry_dump(unit, L2_MOD_FIFOm, entry, BSL_VERBOSE|BSL_LS_SOC_DMA); 2535 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "\n"))); 2536 } 2537 } 2538 2539 int 2540 soc_tr3_l2_overflow_entry_get(int unit, l2_combo_entry_t *entry, soc_mem_t *mem_type) 2541 { 2542 SOC_IF_ERROR_RETURN 2543 (READ_L2_LEARN_INSERT_FAILUREm(unit, COPYNO_ALL, 0, entry->words)); 2544 if (soc_L2_ENTRY_1m_field32_get(unit, entry->words, WIDEf)) { 2545 *mem_type = L2_ENTRY_2m; 2546 } else { 2547 *mem_type = L2_ENTRY_1m; 2548 } 2549 return SOC_E_NONE; 2550 } 2551 2552 int 2553 soc_tr3_l2_overflow_disable(int unit) 2554 { 2555 SOC_IF_ERROR_RETURN 2556 (soc_reg_field32_modify(unit, ISM_INTR_MASKr, REG_PORT_ANY, 2557 L2_LEARN_INSERT_FAILUREf, 0)); 2558 /* Mark as inactive */ 2559 SOC_CONTROL_LOCK(unit); 2560 SOC_CONTROL(unit)->l2_overflow_active = FALSE; 2561 SOC_CONTROL_UNLOCK(unit); 2562 /* But don't disable interrupt as its shared by various ISM events */ 2563 return SOC_E_NONE; 2564 } 2565 2566 int 2567 soc_tr3_l2_overflow_enable(int unit) 2568 { 2569 SOC_IF_ERROR_RETURN 2570 (soc_reg_field32_modify(unit, ISM_INTR_MASKr, REG_PORT_ANY, 2571 L2_LEARN_INSERT_FAILUREf, 1)); 2572 /* Mark as active */ 2573 SOC_CONTROL_LOCK(unit); 2574 SOC_CONTROL(unit)->l2_overflow_active = TRUE; 2575 SOC_CONTROL_UNLOCK(unit); 2576 /* Enable interrupt */ 2577 #ifdef BCM_CMICM_SUPPORT 2578 (void)soc_cmicm_intr1_enable(unit, _SOC_TR3_ISM_INTR_MASK); 2579 #endif 2580 return SOC_E_NONE; 2581 } 2582 2583 int 2584 soc_tr3_l2_overflow_fill(int unit, uint8 zeros_or_ones) 2585 { 2586 l2_learn_insert_failure_entry_t entry; 2587 2588 if (zeros_or_ones) { 2589 sal_memset(&entry, 0xffffffff, sizeof(entry)); 2590 SOC_IF_ERROR_RETURN 2591 (WRITE_L2_LEARN_INSERT_FAILUREm(unit, COPYNO_ALL, 0, &entry)); 2592 } else { 2593 SOC_IF_ERROR_RETURN 2594 (soc_mem_clear(unit, L2_LEARN_INSERT_FAILUREm, COPYNO_ALL, FALSE)); 2595 } 2596 return SOC_E_NONE; 2597 } 2598 2599 void 2600 soc_tr3_l2_overflow_interrupt_handler(int unit) 2601 { 2602 l2_combo_entry_t entry; 2603 soc_mem_t mem_type = INVALIDm; 2604 2605 if (!SOC_CONTROL(unit)->l2_overflow_active) { 2606 LOG_ERROR(BSL_LS_SOC_L2, \ 2607 (BSL_META_U(unit, \ 2608 "Received L2 overflow event with no app handler or"\ 2609 " processing inactive !!\n"))); 2610 } 2611 if (soc_tr3_l2_overflow_disable(unit)) { 2612 return; 2613 } 2614 if (soc_tr3_l2_overflow_entry_get(unit, &entry, &mem_type)) { 2615 return; 2616 } 2617 if (mem_type == INVALIDm) { 2618 return; 2619 } 2620 /* Callback */ 2621 soc_l2_entry_callback(unit, SOC_L2X_ENTRY_OVERFLOW, mem_type, NULL, &entry); 2622 } 2623 2624 int 2625 soc_tr3_l2_overflow_stop(int unit) 2626 { 2627 if (!SOC_CONTROL(unit)->l2_overflow_enable) { 2628 return SOC_E_NONE; 2629 } 2630 SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_fill(unit, 1)); 2631 SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_disable(unit)); 2632 return SOC_E_NONE; 2633 } 2634 2635 int 2636 soc_tr3_l2_overflow_start(int unit) 2637 { 2638 if (!SOC_CONTROL(unit)->l2_overflow_enable) { 2639 return SOC_E_NONE; 2640 } 2641 if (SOC_CONTROL(unit)->l2_overflow_active) { 2642 return SOC_E_NONE; 2643 } 2644 SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_fill(unit, 0)); 2645 SOC_IF_ERROR_RETURN(soc_tr3_l2_overflow_enable(unit)); 2646 return SOC_E_NONE; 2647 } 2648 2649 /* 2650 * External L2 Bulk Delete/Replace Acceleration 2651 * 2652 * Hardware scanning of the external L2 table for bulk delete and 2653 * bulk replace can be a little slow with large L2 tables. This 2654 * code caches enough information on each entry in order to do a 2655 * quick software walk of the table looking for matches. 2656 * 2657 * There are per-vlan min and max indices that are kept so that for 2658 * per-vlan or per-vlan/port scans we only need to look at a subset of 2659 * the entries. 2660 */ 2661 STATIC int 2662 _soc_tr3_l2e_ppa_init(int unit) 2663 { 2664 _soc_tr3_l2e_ppa_info_t *einfo; 2665 _soc_tr3_l2e_ppa_vlan_t *evlan; 2666 int vlan, esize; 2667 2668 if (SOC_CONTROL(unit)->ext_l2_ppa_info != NULL) { 2669 sal_free(SOC_CONTROL(unit)->ext_l2_ppa_info); 2670 SOC_CONTROL(unit)->ext_l2_ppa_info = NULL; 2671 } 2672 if (SOC_CONTROL(unit)->ext_l2_ppa_vlan != NULL) { 2673 sal_free(SOC_CONTROL(unit)->ext_l2_ppa_vlan); 2674 SOC_CONTROL(unit)->ext_l2_ppa_vlan = NULL; 2675 } 2676 if (SOC_CONTROL(unit)->ext_l2_ppa_info_2 != NULL) { 2677 sal_free(SOC_CONTROL(unit)->ext_l2_ppa_info_2); 2678 SOC_CONTROL(unit)->ext_l2_ppa_info_2 = NULL; 2679 } 2680 if (SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 != NULL) { 2681 sal_free(SOC_CONTROL(unit)->ext_l2_ppa_vlan_2); 2682 SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 = NULL; 2683 } 2684 2685 /* EXT_L2_ENTRY_1 */ 2686 esize = soc_mem_index_count(unit, EXT_L2_ENTRY_1m) * 2687 sizeof(_soc_tr3_l2e_ppa_info_t); 2688 einfo = sal_alloc(esize, "_soc_tr3_l2e_ppa_info 1"); 2689 if (einfo == NULL) { 2690 return SOC_E_MEMORY; 2691 } 2692 2693 evlan = sal_alloc(sizeof(_soc_tr3_l2e_ppa_vlan_t), 2694 "_soc_tr3_l2e_ppa_vlan 1"); 2695 if (evlan == NULL) { 2696 sal_free(einfo); 2697 return SOC_E_MEMORY; 2698 } 2699 sal_memset(einfo, 0, esize); 2700 for (vlan = 0; vlan <= VLAN_ID_MAX; vlan++) { 2701 evlan->vlan_min[vlan] = -1; 2702 evlan->vlan_max[vlan] = -1; 2703 } 2704 SOC_CONTROL(unit)->ext_l2_ppa_info = einfo; 2705 SOC_CONTROL(unit)->ext_l2_ppa_vlan = evlan; 2706 2707 /* EXT_L2_ENTRY_2 */ 2708 esize = soc_mem_index_count(unit, EXT_L2_ENTRY_2m) * 2709 sizeof(_soc_tr3_l2e_ppa_info_t); 2710 einfo = sal_alloc(esize, "_soc_tr3_l2e_ppa_info 2"); 2711 if (einfo == NULL) { 2712 return SOC_E_MEMORY; 2713 } 2714 evlan = sal_alloc(sizeof(_soc_tr3_l2e_ppa_vlan_t), 2715 "_soc_tr3_l2e_ppa_vlan 2"); 2716 if (evlan == NULL) { 2717 sal_free(einfo); 2718 return SOC_E_MEMORY; 2719 } 2720 sal_memset(einfo, 0, esize); 2721 for (vlan = 0; vlan <= VLAN_ID_MAX; vlan++) { 2722 evlan->vlan_min[vlan] = -1; 2723 evlan->vlan_max[vlan] = -1; 2724 } 2725 SOC_CONTROL(unit)->ext_l2_ppa_info_2 = einfo; 2726 SOC_CONTROL(unit)->ext_l2_ppa_vlan_2 = evlan; 2727 2728 SOC_CONTROL(unit)->ext_l2_ppa_threshold = 2729 soc_property_get(unit, spn_EXT_L2_USE_HARDWARE_REPLACE_THRESHOLD, 2730 10000); 2731 2732 return SOC_E_NONE; 2733 } 2734 2735 STATIC int 2736 _soc_tr3_l2e_ppa_update(int unit, soc_mem_t mem, int index, uint32 *entry) 2737 { 2738 _soc_tr3_l2e_ppa_info_t *ppa_info; 2739 _soc_tr3_l2e_ppa_vlan_t *ppa_vlan; 2740 uint32 entvalue; 2741 uint32 l2data; 2742 sal_mac_addr_t l2mac; 2743 vlan_id_t vlan, oldvlan; 2744 int vlan_min, vlan_max; 2745 uint32 vdata, vmask; 2746 2747 if (SOC_CONTROL(unit)->ext_l2_ppa_info == NULL) { 2748 if (!soc_mem_is_valid(unit, mem) || 2749 soc_mem_index_count(unit, mem) <= 0) { 2750 return SOC_E_NONE; 2751 } 2752 SOC_IF_ERROR_RETURN(_soc_tr3_l2e_ppa_init(unit)); 2753 } 2754 2755 ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info; 2756 ppa_vlan = SOC_CONTROL(unit)->ext_l2_ppa_vlan; 2757 2758 vlan = 0; 2759 entvalue = 0; 2760 if (entry != NULL) { 2761 l2data = soc_mem_field32_get(unit, mem, entry, FREEf); 2762 if (l2data != 1) { 2763 entvalue |= _SOC_TR3_L2E_VALID; 2764 } 2765 l2data = soc_mem_field32_get(unit, mem, entry, STATIC_BITf); 2766 if (l2data != 0) { 2767 entvalue |= _SOC_TR3_L2E_STATIC; 2768 } 2769 l2data = soc_mem_field32_get(unit, mem, entry, VLAN_IDf); 2770 vlan = l2data; 2771 entvalue |= (l2data & _SOC_TR3_L2E_VLAN_MASK) << _SOC_TR3_L2E_VLAN_SHIFT; 2772 if (soc_mem_field32_get(unit, mem, entry, DEST_TYPEf) == 0x1) { 2773 l2data = soc_mem_field32_get(unit, mem, entry, TGIDf); 2774 entvalue |= _SOC_TR3_L2E_T | 2775 ((l2data & _SOC_TR3_L2E_TRUNK_MASK) << _SOC_TR3_L2E_TRUNK_SHIFT); 2776 } else if (soc_mem_field32_get(unit, mem, entry, DEST_TYPEf) == 0x2) { 2777 l2data = soc_mem_field32_get(unit, mem, entry, DESTINATIONf); 2778 entvalue |= _SOC_TR3_L2E_VP | 2779 ((l2data & _SOC_TR3_L2E_DESTINATION_MASK) << 2780 _SOC_TR3_L2E_DESTINATION_SHIFT); 2781 } else { 2782 l2data = soc_mem_field32_get(unit, mem, entry, MODULE_IDf); 2783 entvalue |= 2784 (l2data & _SOC_TR3_L2E_MOD_MASK) << _SOC_TR3_L2E_MOD_SHIFT; 2785 l2data = soc_mem_field32_get(unit, mem, entry, PORT_NUMf); 2786 entvalue |= 2787 (l2data & _SOC_TR3_L2E_PORT_MASK) << _SOC_TR3_L2E_PORT_SHIFT; 2788 } 2789 soc_mem_mac_addr_get(unit, mem, entry, MAC_ADDRf, l2mac); 2790 } else { 2791 sal_memset(l2mac, 0, sizeof(l2mac)); 2792 } 2793 oldvlan = (ppa_info[index].data >> 16) & 0xfff; 2794 ppa_info[index].data = entvalue; 2795 sal_memcpy(ppa_info[index].mac, l2mac, sizeof(sal_mac_addr_t)); 2796 2797 if (vlan != oldvlan) { /* update vlan_min/max indices */ 2798 if (oldvlan != 0) { 2799 vlan_min = ppa_vlan->vlan_min[oldvlan]; 2800 vlan_max = ppa_vlan->vlan_max[oldvlan]; 2801 vdata = oldvlan << _SOC_TR3_L2E_VLAN_SHIFT; 2802 vmask = _SOC_TR3_L2E_VLAN_MASK << _SOC_TR3_L2E_VLAN_SHIFT; 2803 2804 /* deleted last one? */ 2805 if (index == vlan_min && index == vlan_max) { 2806 ppa_vlan->vlan_min[oldvlan] = -1; 2807 ppa_vlan->vlan_max[oldvlan] = -1; 2808 } else if (index == vlan_min) { 2809 for (; vlan_min <= vlan_max; vlan_min++) { 2810 entvalue = ppa_info[vlan_min].data; 2811 if ((entvalue & vmask) == vdata) { 2812 break; 2813 } 2814 } 2815 ppa_vlan->vlan_min[oldvlan] = vlan_min; 2816 } else if (index == vlan_max) { 2817 for (; vlan_min <= vlan_max; vlan_max--) { 2818 entvalue = ppa_info[vlan_max].data; 2819 if ((entvalue & vmask) == vdata) { 2820 break; 2821 } 2822 } 2823 ppa_vlan->vlan_max[oldvlan] = vlan_max; 2824 } 2825 2826 } 2827 if (vlan != 0) { 2828 vlan_min = ppa_vlan->vlan_min[vlan]; 2829 vlan_max = ppa_vlan->vlan_max[vlan]; 2830 if (vlan_min < 0 || index < vlan_min) { 2831 ppa_vlan->vlan_min[vlan] = index; 2832 } 2833 if (vlan_max < 0 || index > vlan_max) { 2834 ppa_vlan->vlan_max[vlan] = index; 2835 } 2836 } 2837 } 2838 2839 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2840 (BSL_META_U(unit, 2841 "tr3_l2e_ppa %d: index=%d oldvlan=%d min:max %d:%d\n"), 2842 mem == EXT_L2_ENTRY_1m ? 1 : 2, 2843 index, oldvlan, ppa_vlan->vlan_min[oldvlan], 2844 ppa_vlan->vlan_max[oldvlan])); 2845 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2846 (BSL_META_U(unit, 2847 "tr3_l2e_ppa %d: ent=0x%x mac=%x:%x:%x:%x:%x:%x " 2848 "vlan=%d min:max %d:%d\n"), 2849 mem == EXT_L2_ENTRY_1m ? 1 : 2, 2850 ppa_info[index].data, 2851 l2mac[0], l2mac[1], l2mac[2], l2mac[3], l2mac[4], l2mac[5], 2852 vlan, ppa_vlan->vlan_min[vlan], 2853 ppa_vlan->vlan_max[vlan])); 2854 return SOC_E_NONE; 2855 } 2856 2857 int 2858 soc_triumph3_ext_l2_entry_update(int unit, soc_mem_t mem, int index, void *entry) 2859 { 2860 return _soc_tr3_l2e_ppa_update(unit, mem, index, entry); 2861 } 2862 2863 #endif /* BCM_TRIUMPH3_SUPPORT */